Wed Jan 8 2020 09:49:51

Asterisk developer's documentation


tcptls.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007 - 2008, Digium, Inc.
5  *
6  * Luigi Rizzo (TCP and TLS server code)
7  * Brett Bryant <brettbryant@gmail.com> (updated for client support)
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19 
20 /*!
21  * \file
22  * \brief Code to support TCP and TLS server/client
23  *
24  * \author Luigi Rizzo
25  * \author Brett Bryant <brettbryant@gmail.com>
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 434386 $")
35 
36 #ifdef HAVE_FCNTL_H
37 #include <fcntl.h>
38 #endif
39 
40 #include <signal.h>
41 #include <sys/signal.h>
42 
43 #include "asterisk/compat.h"
44 #include "asterisk/tcptls.h"
45 #include "asterisk/http.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/strings.h"
48 #include "asterisk/options.h"
49 #include "asterisk/manager.h"
50 #include "asterisk/astobj2.h"
51 #include "asterisk/pbx.h"
52 
53 /*! ao2 object used for the FILE stream fopencookie()/funopen() cookie. */
55  /*! SSL state if not NULL */
56  SSL *ssl;
57  /*!
58  * \brief Start time from when an I/O sequence must complete
59  * by struct ast_tcptls_stream.timeout.
60  *
61  * \note If struct ast_tcptls_stream.start.tv_sec is zero then
62  * start time is the current I/O request.
63  */
64  struct timeval start;
65  /*!
66  * \brief The socket returned by accept().
67  *
68  * \note Set to -1 if the stream is closed.
69  */
70  int fd;
71  /*!
72  * \brief Timeout in ms relative to struct ast_tcptls_stream.start
73  * to wait for an event on struct ast_tcptls_stream.fd.
74  *
75  * \note Set to -1 to disable timeout.
76  * \note The socket needs to be set to non-blocking for the timeout
77  * feature to work correctly.
78  */
79  int timeout;
80  /*! TRUE if stream can exclusively wait for fd input. */
82 };
83 
85 {
86  ast_assert(stream != NULL);
87 
88  stream->timeout = -1;
89 }
90 
92 {
93  ast_assert(stream != NULL);
94 
95  stream->start.tv_sec = 0;
96  stream->timeout = timeout;
97 }
98 
99 void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout)
100 {
101  ast_assert(stream != NULL);
102 
103  stream->start = start;
104  stream->timeout = timeout;
105 }
106 
107 void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
108 {
109  ast_assert(stream != NULL);
110 
111  stream->exclusive_input = exclusive_input;
112 }
113 
114 /*!
115  * \internal
116  * \brief fopencookie()/funopen() stream read function.
117  *
118  * \param cookie Stream control data.
119  * \param buf Where to put read data.
120  * \param size Size of the buffer.
121  *
122  * \retval number of bytes put into buf.
123  * \retval 0 on end of file.
124  * \retval -1 on error.
125  */
126 static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
127 {
128  struct ast_tcptls_stream *stream = cookie;
129  struct timeval start;
130  int ms;
131  int res;
132 
133  if (!size) {
134  /* You asked for no data you got no data. */
135  return 0;
136  }
137 
138  if (!stream || stream->fd == -1) {
139  errno = EBADF;
140  return -1;
141  }
142 
143  if (stream->start.tv_sec) {
144  start = stream->start;
145  } else {
146  start = ast_tvnow();
147  }
148 
149 #if defined(DO_SSL)
150  if (stream->ssl) {
151  for (;;) {
152  res = SSL_read(stream->ssl, buf, size);
153  if (0 < res) {
154  /* We read some payload data. */
155  return res;
156  }
157  switch (SSL_get_error(stream->ssl, res)) {
158  case SSL_ERROR_ZERO_RETURN:
159  /* Report EOF for a shutdown */
160  ast_debug(1, "TLS clean shutdown alert reading data\n");
161  return 0;
162  case SSL_ERROR_WANT_READ:
163  if (!stream->exclusive_input) {
164  /* We cannot wait for data now. */
165  errno = EAGAIN;
166  return -1;
167  }
168  while ((ms = ast_remaining_ms(start, stream->timeout))) {
169  res = ast_wait_for_input(stream->fd, ms);
170  if (0 < res) {
171  /* Socket is ready to be read. */
172  break;
173  }
174  if (res < 0) {
175  if (errno == EINTR || errno == EAGAIN) {
176  /* Try again. */
177  continue;
178  }
179  ast_debug(1, "TLS socket error waiting for read data: %s\n",
180  strerror(errno));
181  return -1;
182  }
183  }
184  break;
185  case SSL_ERROR_WANT_WRITE:
186  while ((ms = ast_remaining_ms(start, stream->timeout))) {
187  res = ast_wait_for_output(stream->fd, ms);
188  if (0 < res) {
189  /* Socket is ready to be written. */
190  break;
191  }
192  if (res < 0) {
193  if (errno == EINTR || errno == EAGAIN) {
194  /* Try again. */
195  continue;
196  }
197  ast_debug(1, "TLS socket error waiting for write space: %s\n",
198  strerror(errno));
199  return -1;
200  }
201  }
202  break;
203  default:
204  /* Report EOF for an undecoded SSL or transport error. */
205  ast_debug(1, "TLS transport or SSL error reading data\n");
206  return 0;
207  }
208  if (!ms) {
209  /* Report EOF for a timeout */
210  ast_debug(1, "TLS timeout reading data\n");
211  return 0;
212  }
213  }
214  }
215 #endif /* defined(DO_SSL) */
216 
217  for (;;) {
218  res = read(stream->fd, buf, size);
219  if (0 <= res || !stream->exclusive_input) {
220  /* Got data or we cannot wait for it. */
221  return res;
222  }
223  if (errno != EINTR && errno != EAGAIN) {
224  /* Not a retryable error. */
225  ast_debug(1, "TCP socket error reading data: %s\n",
226  strerror(errno));
227  return -1;
228  }
229  ms = ast_remaining_ms(start, stream->timeout);
230  if (!ms) {
231  /* Report EOF for a timeout */
232  ast_debug(1, "TCP timeout reading data\n");
233  return 0;
234  }
235  ast_wait_for_input(stream->fd, ms);
236  }
237 }
238 
239 /*!
240  * \internal
241  * \brief fopencookie()/funopen() stream write function.
242  *
243  * \param cookie Stream control data.
244  * \param buf Where to get data to write.
245  * \param size Size of the buffer.
246  *
247  * \retval number of bytes written from buf.
248  * \retval -1 on error.
249  */
250 static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
251 {
252  struct ast_tcptls_stream *stream = cookie;
253  struct timeval start;
254  int ms;
255  int res;
256  int written;
257  int remaining;
258 
259  if (!size) {
260  /* You asked to write no data you wrote no data. */
261  return 0;
262  }
263 
264  if (!stream || stream->fd == -1) {
265  errno = EBADF;
266  return -1;
267  }
268 
269  if (stream->start.tv_sec) {
270  start = stream->start;
271  } else {
272  start = ast_tvnow();
273  }
274 
275 #if defined(DO_SSL)
276  if (stream->ssl) {
277  written = 0;
278  remaining = size;
279  for (;;) {
280  res = SSL_write(stream->ssl, buf + written, remaining);
281  if (res == remaining) {
282  /* Everything was written. */
283  return size;
284  }
285  if (0 < res) {
286  /* Successfully wrote part of the buffer. Try to write the rest. */
287  written += res;
288  remaining -= res;
289  continue;
290  }
291  switch (SSL_get_error(stream->ssl, res)) {
292  case SSL_ERROR_ZERO_RETURN:
293  ast_debug(1, "TLS clean shutdown alert writing data\n");
294  if (written) {
295  /* Report partial write. */
296  return written;
297  }
298  errno = EBADF;
299  return -1;
300  case SSL_ERROR_WANT_READ:
301  ms = ast_remaining_ms(start, stream->timeout);
302  if (!ms) {
303  /* Report partial write. */
304  ast_debug(1, "TLS timeout writing data (want read)\n");
305  return written;
306  }
307  ast_wait_for_input(stream->fd, ms);
308  break;
309  case SSL_ERROR_WANT_WRITE:
310  ms = ast_remaining_ms(start, stream->timeout);
311  if (!ms) {
312  /* Report partial write. */
313  ast_debug(1, "TLS timeout writing data (want write)\n");
314  return written;
315  }
316  ast_wait_for_output(stream->fd, ms);
317  break;
318  default:
319  /* Undecoded SSL or transport error. */
320  ast_debug(1, "TLS transport or SSL error writing data\n");
321  if (written) {
322  /* Report partial write. */
323  return written;
324  }
325  errno = EBADF;
326  return -1;
327  }
328  }
329  }
330 #endif /* defined(DO_SSL) */
331 
332  written = 0;
333  remaining = size;
334  for (;;) {
335  res = write(stream->fd, buf + written, remaining);
336  if (res == remaining) {
337  /* Yay everything was written. */
338  return size;
339  }
340  if (0 < res) {
341  /* Successfully wrote part of the buffer. Try to write the rest. */
342  written += res;
343  remaining -= res;
344  continue;
345  }
346  if (errno != EINTR && errno != EAGAIN) {
347  /* Not a retryable error. */
348  ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
349  if (written) {
350  return written;
351  }
352  return -1;
353  }
354  ms = ast_remaining_ms(start, stream->timeout);
355  if (!ms) {
356  /* Report partial write. */
357  ast_debug(1, "TCP timeout writing data\n");
358  return written;
359  }
360  ast_wait_for_output(stream->fd, ms);
361  }
362 }
363 
364 /*!
365  * \internal
366  * \brief fopencookie()/funopen() stream close function.
367  *
368  * \param cookie Stream control data.
369  *
370  * \retval 0 on success.
371  * \retval -1 on error.
372  */
373 static int tcptls_stream_close(void *cookie)
374 {
375  struct ast_tcptls_stream *stream = cookie;
376 
377  if (!stream) {
378  errno = EBADF;
379  return -1;
380  }
381 
382  if (stream->fd != -1) {
383 #if defined(DO_SSL)
384  if (stream->ssl) {
385  int res;
386 
387  /*
388  * According to the TLS standard, it is acceptable for an
389  * application to only send its shutdown alert and then
390  * close the underlying connection without waiting for
391  * the peer's response (this way resources can be saved,
392  * as the process can already terminate or serve another
393  * connection).
394  */
395  res = SSL_shutdown(stream->ssl);
396  if (res < 0) {
397  ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n",
398  SSL_get_error(stream->ssl, res));
399  }
400 
401  if (!stream->ssl->server) {
402  /* For client threads, ensure that the error stack is cleared */
403  ERR_remove_state(0);
404  }
405 
406  SSL_free(stream->ssl);
407  stream->ssl = NULL;
408  }
409 #endif /* defined(DO_SSL) */
410 
411  /*
412  * Issuing shutdown() is necessary here to avoid a race
413  * condition where the last data written may not appear
414  * in the TCP stream. See ASTERISK-23548
415  */
416  shutdown(stream->fd, SHUT_RDWR);
417  if (close(stream->fd)) {
418  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
419  }
420  stream->fd = -1;
421  }
422  ao2_t_ref(stream, -1, "Closed tcptls stream cookie");
423 
424  return 0;
425 }
426 
427 /*!
428  * \internal
429  * \brief fopencookie()/funopen() stream destructor function.
430  *
431  * \param cookie Stream control data.
432  *
433  * \return Nothing
434  */
435 static void tcptls_stream_dtor(void *cookie)
436 {
437 #ifdef AST_DEVMODE
438  /* Since the ast_assert below is the only one using stream,
439  * and ast_assert is only available with AST_DEVMODE, we
440  * put this in a conditional to avoid compiler warnings. */
441  struct ast_tcptls_stream *stream = cookie;
442 #endif
443 
444  ast_assert(stream->fd == -1);
445 }
446 
447 /*!
448  * \internal
449  * \brief fopencookie()/funopen() stream allocation function.
450  *
451  * \retval stream_cookie on success.
452  * \retval NULL on error.
453  */
455 {
456  struct ast_tcptls_stream *stream;
457 
458  stream = ao2_alloc(sizeof(*stream), tcptls_stream_dtor);
459  if (stream) {
460  stream->fd = -1;
461  stream->timeout = -1;
462  }
463  return stream;
464 }
465 
466 /*!
467  * \internal
468  * \brief Open a custom FILE stream for tcptls.
469  *
470  * \param stream Stream cookie control data.
471  * \param ssl SSL state if not NULL.
472  * \param fd Socket file descriptor.
473  * \param timeout ms to wait for an event on fd. -1 if timeout disabled.
474  *
475  * \retval fp on success.
476  * \retval NULL on error.
477  */
478 static FILE *tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
479 {
480  FILE *fp;
481 
482 #if defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
483  static const cookie_io_functions_t cookie_funcs = {
486  NULL,
488  };
489 #endif /* defined(HAVE_FOPENCOOKIE) */
490 
491  if (fd == -1) {
492  /* Socket not open. */
493  return NULL;
494  }
495 
496  stream->ssl = ssl;
497  stream->fd = fd;
498  stream->timeout = timeout;
499  ao2_t_ref(stream, +1, "Opening tcptls stream cookie");
500 
501 #if defined(HAVE_FUNOPEN) /* the BSD interface */
502  fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL,
504 #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
505  fp = fopencookie(stream, "w+", cookie_funcs);
506 #else
507  /* could add other methods here */
508  ast_debug(2, "No stream FILE methods attempted!\n");
509  fp = NULL;
510 #endif
511 
512  if (!fp) {
513  stream->fd = -1;
514  ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie");
515  }
516  return fp;
517 }
518 
519 HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count)
520 {
521  if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
522  ast_log(LOG_ERROR, "TCP/TLS read called on invalid stream.\n");
523  errno = EIO;
524  return -1;
525  }
526 
527  return tcptls_stream_read(tcptls_session->stream_cookie, buf, count);
528 }
529 
530 HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count)
531 {
532  if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
533  ast_log(LOG_ERROR, "TCP/TLS write called on invalid stream.\n");
534  errno = EIO;
535  return -1;
536  }
537 
538  return tcptls_stream_write(tcptls_session->stream_cookie, buf, count);
539 }
540 
541 static void session_instance_destructor(void *obj)
542 {
543  struct ast_tcptls_session_instance *i = obj;
544 
545  if (i->stream_cookie) {
546  ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance");
547  i->stream_cookie = NULL;
548  }
550  ast_mutex_destroy(&i->lock);
551 }
552 
553 /*! \brief
554 * creates a FILE * from the fd passed by the accept thread.
555 * This operation is potentially expensive (certificate verification),
556 * so we do it in the child thread context.
557 *
558 * \note must decrement ref count before returning NULL on error
559 */
560 static void *handle_tcptls_connection(void *data)
561 {
562  struct ast_tcptls_session_instance *tcptls_session = data;
563 #ifdef DO_SSL
564  int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept;
565  int ret;
566  char err[256];
567 #endif
568 
569  /* TCP/TLS connections are associated with external protocols, and
570  * should not be allowed to execute 'dangerous' functions. This may
571  * need to be pushed down into the individual protocol handlers, but
572  * this seems like a good general policy.
573  */
575  ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n");
576  ast_tcptls_close_session_file(tcptls_session);
577  ao2_ref(tcptls_session, -1);
578  return NULL;
579  }
580 
581  tcptls_session->stream_cookie = tcptls_stream_alloc();
582  if (!tcptls_session->stream_cookie) {
583  ast_tcptls_close_session_file(tcptls_session);
584  ao2_ref(tcptls_session, -1);
585  return NULL;
586  }
587 
588  /*
589  * open a FILE * as appropriate.
590  */
591  if (!tcptls_session->parent->tls_cfg) {
592  tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL,
593  tcptls_session->fd, -1);
594  if (tcptls_session->f) {
595  if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) {
596  ast_tcptls_close_session_file(tcptls_session);
597  }
598  }
599  }
600 #ifdef DO_SSL
601  else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
602  SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
603  if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
604  ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
605  } else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
606  tcptls_session->ssl, tcptls_session->fd, -1))) {
607  if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
608  || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
609  X509 *peer;
610  long res;
611  peer = SSL_get_peer_certificate(tcptls_session->ssl);
612  if (!peer) {
613  ast_log(LOG_ERROR, "No peer SSL certificate to verify\n");
614  ast_tcptls_close_session_file(tcptls_session);
615  ao2_ref(tcptls_session, -1);
616  return NULL;
617  }
618 
619  res = SSL_get_verify_result(tcptls_session->ssl);
620  if (res != X509_V_OK) {
621  ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
622  X509_free(peer);
623  ast_tcptls_close_session_file(tcptls_session);
624  ao2_ref(tcptls_session, -1);
625  return NULL;
626  }
627  if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
628  ASN1_STRING *str;
629  unsigned char *str2;
630  X509_NAME *name = X509_get_subject_name(peer);
631  int pos = -1;
632  int found = 0;
633 
634  for (;;) {
635  /* Walk the certificate to check all available "Common Name" */
636  /* XXX Probably should do a gethostbyname on the hostname and compare that as well */
637  pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
638  if (pos < 0)
639  break;
640  str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
641  ret = ASN1_STRING_to_UTF8(&str2, str);
642  if (ret < 0) {
643  continue;
644  }
645 
646  if (str2) {
647  if (strlen((char *) str2) != ret) {
648  ast_log(LOG_WARNING, "Invalid certificate common name length (contains NULL bytes?)\n");
649  } else if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) {
650  found = 1;
651  }
652  ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2);
653  OPENSSL_free(str2);
654  }
655  if (found)
656  break;
657  }
658  if (!found) {
659  ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname);
660  X509_free(peer);
661  ast_tcptls_close_session_file(tcptls_session);
662  ao2_ref(tcptls_session, -1);
663  return NULL;
664  }
665  }
666  X509_free(peer);
667  }
668  }
669  if (!tcptls_session->f) /* no success opening descriptor stacking */
670  SSL_free(tcptls_session->ssl);
671  }
672 #endif /* DO_SSL */
673 
674  if (!tcptls_session->f) {
675  ast_tcptls_close_session_file(tcptls_session);
676  ast_log(LOG_WARNING, "FILE * open failed!\n");
677 #ifndef DO_SSL
678  if (tcptls_session->parent->tls_cfg) {
679  ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n");
680  }
681 #endif
682  ao2_ref(tcptls_session, -1);
683  return NULL;
684  }
685 
686  if (tcptls_session->parent->worker_fn) {
687  return tcptls_session->parent->worker_fn(tcptls_session);
688  } else {
689  return tcptls_session;
690  }
691 }
692 
693 void *ast_tcptls_server_root(void *data)
694 {
695  struct ast_tcptls_session_args *desc = data;
696  int fd;
697  struct ast_sockaddr addr;
698  struct ast_tcptls_session_instance *tcptls_session;
699  pthread_t launched;
700 
701  for (;;) {
702  int i, flags;
703 
704  if (desc->periodic_fn)
705  desc->periodic_fn(desc);
706  i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
707  if (i <= 0)
708  continue;
709  fd = ast_accept(desc->accept_fd, &addr);
710  if (fd < 0) {
711  if ((errno != EAGAIN) && (errno != EINTR))
712  ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
713  continue;
714  }
715  tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
716  if (!tcptls_session) {
717  ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
718  if (close(fd)) {
719  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
720  }
721  continue;
722  }
723 
724  ast_mutex_init(&tcptls_session->lock);
725  tcptls_session->overflow_buf = ast_str_create(128);
726 
727  flags = fcntl(fd, F_GETFL);
728  fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
729  tcptls_session->fd = fd;
730  tcptls_session->parent = desc;
731  ast_sockaddr_copy(&tcptls_session->remote_address, &addr);
732 
733  tcptls_session->client = 0;
734 
735  /* This thread is now the only place that controls the single ref to tcptls_session */
736  if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
737  ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
738  ast_tcptls_close_session_file(tcptls_session);
739  ao2_ref(tcptls_session, -1);
740  }
741  }
742  return NULL;
743 }
744 
745 static int __ssl_setup(struct ast_tls_config *cfg, int client)
746 {
747 #ifndef DO_SSL
748  cfg->enabled = 0;
749  return 0;
750 #else
751  int disable_ssl = 0;
752 
753  if (!cfg->enabled)
754  return 0;
755 
756  /* Get rid of an old SSL_CTX since we're about to
757  * allocate a new one
758  */
759  if (cfg->ssl_ctx) {
760  SSL_CTX_free(cfg->ssl_ctx);
761  cfg->ssl_ctx = NULL;
762  }
763 
764  if (client) {
765 #ifndef OPENSSL_NO_SSL2
767  ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
768  cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
769  } else
770 #endif
772  ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
773  cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
774  } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
775  cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
776  } else {
777  disable_ssl = 1;
778  cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
779  }
780  } else {
781  disable_ssl = 1;
782  cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
783  }
784 
785  if (!cfg->ssl_ctx) {
786  ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
787  cfg->enabled = 0;
788  return 0;
789  }
790 
791  /* Due to the POODLE vulnerability, completely disable
792  * SSLv2 and SSLv3 if we are not explicitly told to use
793  * them. SSLv23_*_method supports TLSv1+.
794  */
795  if (disable_ssl) {
796  long ssl_opts;
797 
798  ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
799  SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
800  }
801 
802  SSL_CTX_set_verify(cfg->ssl_ctx,
803  ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
804  NULL);
805 
806  if (!ast_strlen_zero(cfg->certfile)) {
807  char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
808  if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
809  if (!client) {
810  /* Clients don't need a certificate, but if its setup we can use it */
811  ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile);
812  cfg->enabled = 0;
813  SSL_CTX_free(cfg->ssl_ctx);
814  cfg->ssl_ctx = NULL;
815  return 0;
816  }
817  }
818  if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
819  if (!client) {
820  /* Clients don't need a private key, but if its setup we can use it */
821  ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate);
822  cfg->enabled = 0;
823  SSL_CTX_free(cfg->ssl_ctx);
824  cfg->ssl_ctx = NULL;
825  return 0;
826  }
827  }
828  }
829  if (!ast_strlen_zero(cfg->cipher)) {
830  if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
831  if (!client) {
832  ast_verb(0, "SSL cipher error <%s>", cfg->cipher);
833  cfg->enabled = 0;
834  SSL_CTX_free(cfg->ssl_ctx);
835  cfg->ssl_ctx = NULL;
836  return 0;
837  }
838  }
839  }
840  if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
841  if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0)
842  ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
843  }
844 
845  ast_verb(0, "SSL certificate ok\n");
846  return 1;
847 #endif
848 }
849 
851 {
852  return __ssl_setup(cfg, 0);
853 }
854 
856 {
857 #ifdef DO_SSL
858  if (cfg->ssl_ctx) {
859  SSL_CTX_free(cfg->ssl_ctx);
860  cfg->ssl_ctx = NULL;
861  }
862 #endif
863 }
864 
866 {
868  int flags;
869 
870  if (!(desc = tcptls_session->parent)) {
871  goto client_start_error;
872  }
873 
874  if (ast_connect(desc->accept_fd, &desc->remote_address)) {
875  ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n",
876  desc->name,
878  strerror(errno));
879  goto client_start_error;
880  }
881 
882  flags = fcntl(desc->accept_fd, F_GETFL);
883  fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
884 
885  if (desc->tls_cfg) {
886  desc->tls_cfg->enabled = 1;
887  __ssl_setup(desc->tls_cfg, 1);
888  }
889 
890  return handle_tcptls_connection(tcptls_session);
891 
892 client_start_error:
893  if (desc) {
894  close(desc->accept_fd);
895  desc->accept_fd = -1;
896  }
897  ao2_ref(tcptls_session, -1);
898  return NULL;
899 
900 }
901 
903 {
904  int x = 1;
905  struct ast_tcptls_session_instance *tcptls_session = NULL;
906 
907  /* Do nothing if nothing has changed */
908  if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
909  ast_debug(1, "Nothing changed in %s\n", desc->name);
910  return NULL;
911  }
912 
913  /* If we return early, there is no connection */
915 
916  if (desc->accept_fd != -1)
917  close(desc->accept_fd);
918 
919  desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
920  AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
921  if (desc->accept_fd < 0) {
922  ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
923  desc->name, strerror(errno));
924  return NULL;
925  }
926 
927  /* if a local address was specified, bind to it so the connection will
928  originate from the desired address */
929  if (!ast_sockaddr_isnull(&desc->local_address)) {
930  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
931  if (ast_bind(desc->accept_fd, &desc->local_address)) {
932  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
933  desc->name,
935  strerror(errno));
936  goto error;
937  }
938  }
939 
940  if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor)))
941  goto error;
942 
943  ast_mutex_init(&tcptls_session->lock);
944  tcptls_session->overflow_buf = ast_str_create(128);
945  tcptls_session->client = 1;
946  tcptls_session->fd = desc->accept_fd;
947  tcptls_session->parent = desc;
948  tcptls_session->parent->worker_fn = NULL;
949  ast_sockaddr_copy(&tcptls_session->remote_address,
950  &desc->remote_address);
951 
952  /* Set current info */
954  return tcptls_session;
955 
956 error:
957  close(desc->accept_fd);
958  desc->accept_fd = -1;
959  if (tcptls_session)
960  ao2_ref(tcptls_session, -1);
961  return NULL;
962 }
963 
965 {
966  int flags;
967  int x = 1;
968 
969  /* Do nothing if nothing has changed */
970  if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
971  ast_debug(1, "Nothing changed in %s\n", desc->name);
972  return;
973  }
974 
975  /* If we return early, there is no one listening */
977 
978  /* Shutdown a running server if there is one */
979  if (desc->master != AST_PTHREADT_NULL) {
980  pthread_cancel(desc->master);
981  pthread_kill(desc->master, SIGURG);
982  pthread_join(desc->master, NULL);
983  }
984 
985  if (desc->accept_fd != -1)
986  close(desc->accept_fd);
987 
988  /* If there's no new server, stop here */
989  if (ast_sockaddr_isnull(&desc->local_address)) {
990  ast_debug(2, "Server disabled: %s\n", desc->name);
991  return;
992  }
993 
994  desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ?
995  AF_INET6 : AF_INET, SOCK_STREAM, 0);
996  if (desc->accept_fd < 0) {
997  ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
998  return;
999  }
1000 
1001  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1002  if (ast_bind(desc->accept_fd, &desc->local_address)) {
1003  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
1004  desc->name,
1006  strerror(errno));
1007  goto error;
1008  }
1009  if (listen(desc->accept_fd, 10)) {
1010  ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
1011  goto error;
1012  }
1013  flags = fcntl(desc->accept_fd, F_GETFL);
1014  fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
1015  if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
1016  ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
1017  desc->name,
1019  strerror(errno));
1020  goto error;
1021  }
1022 
1023  /* Set current info */
1025 
1026  return;
1027 
1028 error:
1029  close(desc->accept_fd);
1030  desc->accept_fd = -1;
1031 }
1032 
1034 {
1035  if (tcptls_session->f) {
1036  fflush(tcptls_session->f);
1037  if (fclose(tcptls_session->f)) {
1038  ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
1039  }
1040  tcptls_session->f = NULL;
1041  tcptls_session->fd = -1;
1042  } else if (tcptls_session->fd != -1) {
1043  /*
1044  * Issuing shutdown() is necessary here to avoid a race
1045  * condition where the last data written may not appear
1046  * in the TCP stream. See ASTERISK-23548
1047  */
1048  shutdown(tcptls_session->fd, SHUT_RDWR);
1049  if (close(tcptls_session->fd)) {
1050  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
1051  }
1052  tcptls_session->fd = -1;
1053  } else {
1054  ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
1055  }
1056 }
1057 
1059 {
1060  if (desc->master != AST_PTHREADT_NULL) {
1061  pthread_cancel(desc->master);
1062  pthread_kill(desc->master, SIGURG);
1063  pthread_join(desc->master, NULL);
1064  desc->master = AST_PTHREADT_NULL;
1065  }
1066  if (desc->accept_fd != -1)
1067  close(desc->accept_fd);
1068  desc->accept_fd = -1;
1069  ast_debug(2, "Stopped server :: %s\n", desc->name);
1070 }
1071 
1072 int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
1073 {
1074  if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
1075  tls_cfg->enabled = ast_true(value) ? 1 : 0;
1076  } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
1077  ast_free(tls_cfg->certfile);
1078  tls_cfg->certfile = ast_strdup(value);
1079  } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
1080  ast_free(tls_cfg->pvtfile);
1081  tls_cfg->pvtfile = ast_strdup(value);
1082  } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
1083  ast_free(tls_cfg->cipher);
1084  tls_cfg->cipher = ast_strdup(value);
1085  } else if (!strcasecmp(varname, "tlscafile")) {
1086  ast_free(tls_cfg->cafile);
1087  tls_cfg->cafile = ast_strdup(value);
1088  } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
1089  ast_free(tls_cfg->capath);
1090  tls_cfg->capath = ast_strdup(value);
1091  } else if (!strcasecmp(varname, "tlsverifyclient")) {
1092  ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT);
1093  } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
1095  } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
1096  if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
1097  ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
1098  } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
1099  if (!strcasecmp(value, "tlsv1")) {
1103  } else if (!strcasecmp(value, "sslv3")) {
1107  } else if (!strcasecmp(value, "sslv2")) {
1111  }
1112  } else {
1113  return -1;
1114  }
1115 
1116  return 0;
1117 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
Definition: tcptls.c:126
char * pvtfile
Definition: tcptls.h:88
Asterisk main include file. File version handling, generic pbx functions.
static void tcptls_stream_dtor(void *cookie)
Definition: tcptls.c:435
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 ...
Definition: tcptls.c:964
String manipulation functions.
void ast_ssl_teardown(struct ast_tls_config *cfg)
free resources used by an SSL server
Definition: tcptls.c:855
#define ast_strdup(a)
Definition: astmm.h:109
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
Definition: tcptls.c:850
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
Definition: tcptls.c:64
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:121
struct ast_str * overflow_buf
Definition: tcptls.h:216
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
static void * handle_tcptls_connection(void *data)
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (ce...
Definition: tcptls.c:560
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
arguments for the accepting thread
Definition: tcptls.h:123
#define ast_assert(a)
Definition: utils.h:738
const char * str
Definition: app_jack.c:144
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:300
int value
Definition: syslog.c:39
Generic support for tcp/tls servers in Asterisk.
static FILE * tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
Definition: tcptls.c:478
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
Socket address structure.
Definition: netsock2.h:63
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition: netsock2.c:462
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:431
#define ast_verb(level,...)
Definition: logger.h:243
Utility functions.
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:106
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. &quot;null&quot; in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:93
Support for Private Asterisk HTTP Servers.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
void * ast_tcptls_server_root(void *)
Definition: tcptls.c:693
int ast_accept(int sockfd, struct ast_sockaddr *addr)
Wrapper around accept(2) that uses struct ast_sockaddr.
Definition: netsock2.c:456
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: config.c:2805
#define AST_PTHREADT_NULL
Definition: lock.h:65
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct ast_sockaddr remote_address
Definition: tcptls.h:126
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static int __ssl_setup(struct ast_tls_config *cfg, int client)
Definition: tcptls.c:745
void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.
Definition: tcptls.c:107
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
Core PBX routines and definitions.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static const char desc[]
Definition: cdr_radius.c:85
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
#define HOOK_T
Definition: tcptls.h:225
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:1615
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *ser, void *buf, size_t count)
Definition: tcptls.c:519
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
void *(* worker_fn)(void *)
Definition: tcptls.h:135
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static void session_instance_destructor(void *obj)
Definition: tcptls.c:541
char * cafile
Definition: tcptls.h:90
void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout)
Set the TCP/TLS stream inactivity timeout timer.
Definition: tcptls.c:91
int errno
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
static struct ast_tcptls_stream * tcptls_stream_alloc(void)
Definition: tcptls.c:454
struct ast_sockaddr old_address
Definition: tcptls.h:125
char * certfile
Definition: tcptls.h:87
#define ast_clear_flag(p, flag)
Definition: utils.h:77
int exclusive_input
Definition: tcptls.c:81
const char * name
Definition: tcptls.h:136
int fd
The socket returned by accept().
Definition: tcptls.c:70
int ast_wait_for_output(int fd, int ms)
Definition: utils.c:1265
HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, const void *buf, size_t count)
Definition: tcptls.c:530
#define LEN_T
Definition: tcptls.h:226
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
Closes a tcptls session instance&#39;s file and/or file descriptor. The tcptls_session will be set to NUL...
Definition: tcptls.c:1033
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
static int tcptls_stream_close(void *cookie)
Definition: tcptls.c:373
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
Definition: tcptls.c:902
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
Definition: pbx.c:4072
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: tcptls.c:1072
Options provided by main asterisk program.
struct ast_flags flags
Definition: tcptls.h:92
SSL_CTX * ssl_ctx
Definition: tcptls.h:93
void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout)
Set the TCP/TLS stream I/O sequence timeout timer.
Definition: tcptls.c:99
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&#39;s ref count is decremented...
Definition: tcptls.c:865
char * capath
Definition: tcptls.h:91
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
Definition: tcptls.c:1058
struct ast_tls_config * tls_cfg
Definition: tcptls.h:128
#define ast_mutex_init(pmutex)
Definition: lock.h:152
struct ast_sockaddr local_address
Definition: tcptls.h:124
void(* periodic_fn)(void *)
Definition: tcptls.h:134
#define ast_mutex_destroy(a)
Definition: lock.h:154
void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream)
Disable the TCP/TLS stream timeout timer.
Definition: tcptls.c:84
char * cipher
Definition: tcptls.h:89
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:418
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:467
char hostname[MAXHOSTNAMELEN]
Definition: tcptls.h:127
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
Definition: tcptls.c:250
struct ast_sockaddr remote_address
Definition: tcptls.h:207
void *(* accept_fn)(void *)
Definition: tcptls.h:133
int enabled
Definition: tcptls.h:86