forked from Mirrors/freeswitch
Tue Dec 16 16:19:37 CST 2008 Jarod Neuner <janeuner@networkharbor.com>
* Early TLS Handshake and Verification tport_type_tls.c: * tport_tls_accept(): - Replaces tport_accept for incoming TLS connections. * tport_tls_connect(): - Replaces tport_base_connect() for outgoing TLS connections. tport_tls.c: * tls_t now use a memory home instead of malloc. * removed tls_check_hosts() * tls_connect(): - Replaces tport_base_connect for TLS connection setup. - Completes TLS handshake and verifies peer certificates. - Destroys suspect TLS connections before sending/receiving payload. - Populates a su_strlst_t with subjects from the peer certificate. tport.c: * tport_is_verified() - true if peer certificate validated successfully * tport_delivered_from_subjects() - Certificate subjects listed in the peer certificate. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11769 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
ece5252042
commit
52fa079b2b
@ -1 +1 @@
|
||||
Wed Feb 11 10:10:42 CST 2009
|
||||
Wed Feb 11 10:11:23 CST 2009
|
||||
|
@ -36,6 +36,9 @@
|
||||
#ifndef SU_H
|
||||
#include <sofia-sip/su.h>
|
||||
#endif
|
||||
#ifndef SU_STRLST_H
|
||||
#include <sofia-sip/su_strlst.h>
|
||||
#endif
|
||||
#ifndef SU_WAIT_H
|
||||
#include <sofia-sip/su_wait.h>
|
||||
#endif
|
||||
@ -267,6 +270,9 @@ TPORT_DLL int tport_is_tcp(tport_t const *self);
|
||||
/** Test if transport has TLS. */
|
||||
TPORT_DLL int tport_has_tls(tport_t const *tport);
|
||||
|
||||
/** Test if transport provided a verified certificate chain (TLS only) */
|
||||
TPORT_DLL int tport_is_verified(tport_t const *tport);
|
||||
|
||||
/** Return true if transport is being updated. */
|
||||
TPORT_DLL int tport_is_updating(tport_t const *self);
|
||||
|
||||
@ -332,6 +338,9 @@ TPORT_DLL tport_t *tport_delivered_by(tport_t const *tp, msg_t const *msg);
|
||||
TPORT_DLL int tport_delivered_from(tport_t *tp, msg_t const *msg,
|
||||
tp_name_t name[1]);
|
||||
|
||||
/** Return TLS Subjects provided by the source transport */
|
||||
TPORT_DLL su_strlst_t *tport_delivered_from_subjects(tport_t *tp, msg_t const *msg);
|
||||
|
||||
/** Check if transport named is already resolved */
|
||||
TPORT_DLL int tport_name_is_resolved(tp_name_t const *);
|
||||
|
||||
|
@ -268,7 +268,12 @@ int tport_has_ip6(tport_t const *self)
|
||||
int tport_has_tls(tport_t const *self)
|
||||
{
|
||||
return self && self->tp_pri->pri_has_tls;
|
||||
}
|
||||
|
||||
/** Return true if transport certificate verified successfully */
|
||||
int tport_is_verified(tport_t const *self)
|
||||
{
|
||||
return tport_has_tls(self) && self->tp_verified;
|
||||
}
|
||||
|
||||
/** Return true if transport is being updated. */
|
||||
@ -3040,6 +3045,17 @@ int tport_delivered_from(tport_t *tp, msg_t const *msg, tp_name_t name[1])
|
||||
}
|
||||
}
|
||||
|
||||
/** Return TLS Subjects provided by the source transport */
|
||||
su_strlst_t *tport_delivered_from_subjects(tport_t *tp, msg_t const *msg)
|
||||
{
|
||||
if (tp && msg && msg == tp->tp_master->mr_delivery->d_msg) {
|
||||
tport_t *tp_sec = tp->tp_master->mr_delivery->d_tport;
|
||||
return (tp_sec) ? tp_sec->tp_subjects : NULL;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return UDVM used to decompress the message. */
|
||||
int
|
||||
tport_delivered_with_comp(tport_t *tp, msg_t const *msg,
|
||||
|
@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include <sofia-sip/su_uniqueid.h>
|
||||
#include <sofia-sip/su_strlst.h>
|
||||
|
||||
#ifndef MSG_ADDR_H
|
||||
#include <sofia-sip/msg_addr.h>
|
||||
@ -155,6 +156,7 @@ struct tport_s {
|
||||
unsigned tp_has_stun_server:1;
|
||||
unsigned tp_trunc:1;
|
||||
unsigned tp_is_connected:1; /**< Connection is established */
|
||||
unsigned tp_verified:1; /**< Certificate Chain was verified */
|
||||
unsigned:0;
|
||||
|
||||
tport_t *tp_left, *tp_right, *tp_dad; /**< Links in tport tree */
|
||||
@ -177,6 +179,12 @@ struct tport_s {
|
||||
* or peer name (if secondary).
|
||||
*/
|
||||
|
||||
su_strlst_t *tp_subjects; /**< Transport Subjects.
|
||||
*
|
||||
* Subject Name(s) provided by the
|
||||
* peer in a TLS connection (if secondary).
|
||||
*/
|
||||
|
||||
#define tp_protoname tp_name->tpn_proto
|
||||
#define tp_canon tp_name->tpn_canon
|
||||
#define tp_host tp_name->tpn_host
|
||||
|
@ -35,9 +35,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#define OPENSSL_NO_KRB5 oh-no
|
||||
#define SU_WAKEUP_ARG_T struct tport_s
|
||||
|
||||
#include <sofia-sip/su_types.h>
|
||||
#include <sofia-sip/su.h>
|
||||
#include <sofia-sip/su_alloc.h>
|
||||
#include <sofia-sip/su_wait.h>
|
||||
|
||||
#include <openssl/lhash.h>
|
||||
@ -61,18 +63,21 @@
|
||||
#endif
|
||||
|
||||
#include "tport_tls.h"
|
||||
#include "tport_internal.h"
|
||||
|
||||
char const tls_version[] = OPENSSL_VERSION_TEXT;
|
||||
|
||||
enum { tls_master, tls_slave };
|
||||
enum { tls_master = 0, tls_slave = 1};
|
||||
|
||||
struct tls_s {
|
||||
su_home_t home[1];
|
||||
SSL_CTX *ctx;
|
||||
SSL *con;
|
||||
BIO *bio_con;
|
||||
int type;
|
||||
int verified;
|
||||
unsigned int type:1,
|
||||
accept:1,
|
||||
verify_outgoing:1,
|
||||
verify_incoming:1,
|
||||
verified:1;
|
||||
|
||||
/* Receiving */
|
||||
int read_events;
|
||||
@ -85,7 +90,7 @@ struct tls_s {
|
||||
size_t write_buffer_len;
|
||||
|
||||
/* Host names */
|
||||
char *hosts[TLS_MAX_HOSTS + 1];
|
||||
su_strlst_t *subject;
|
||||
};
|
||||
|
||||
enum { tls_buffer_size = 16384 };
|
||||
@ -122,10 +127,11 @@ void tls_log_errors(unsigned level, char const *s, unsigned long e)
|
||||
static
|
||||
tls_t *tls_create(int type)
|
||||
{
|
||||
tls_t *tls = calloc(1, sizeof(*tls));
|
||||
tls_t *tls = su_home_new(sizeof(*tls));
|
||||
memset(((void *)tls) + sizeof(su_home_t), 0, sizeof(*tls) - sizeof(su_home_t));
|
||||
|
||||
if (tls)
|
||||
tls->type = type;
|
||||
tls->type = type == tls_master ? tls_master : tls_slave;
|
||||
|
||||
return tls;
|
||||
}
|
||||
@ -268,6 +274,8 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
|
||||
ti->verify_peer == 1 ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
|
||||
tls_verify_cb);
|
||||
|
||||
tls->verify_incoming = tls->verify_outgoing = ti->verify_peer ? 1 : 0;
|
||||
|
||||
if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) {
|
||||
SU_DEBUG_1(("%s: error setting cipher list\n", "tls_init_context"));
|
||||
tls_log_errors(1, "tls_init_context", 0);
|
||||
@ -280,14 +288,9 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
|
||||
|
||||
void tls_free(tls_t *tls)
|
||||
{
|
||||
int k;
|
||||
|
||||
if (!tls)
|
||||
return;
|
||||
|
||||
if (tls->read_buffer)
|
||||
free(tls->read_buffer), tls->read_buffer = NULL;
|
||||
|
||||
if (tls->con != NULL)
|
||||
SSL_shutdown(tls->con);
|
||||
|
||||
@ -297,12 +300,7 @@ void tls_free(tls_t *tls)
|
||||
if (tls->bio_con != NULL)
|
||||
BIO_free(tls->bio_con);
|
||||
|
||||
for (k = 0; k < TLS_MAX_HOSTS; k++)
|
||||
if (tls->hosts[k]) {
|
||||
free(tls->hosts[k]), tls->hosts[k] = NULL;
|
||||
}
|
||||
|
||||
free(tls);
|
||||
su_home_unref(tls->home);
|
||||
}
|
||||
|
||||
int tls_get_socket(tls_t *tls)
|
||||
@ -369,9 +367,10 @@ tls_t *tls_clone(tls_t *master, int sock, int accept)
|
||||
|
||||
if (tls) {
|
||||
tls->ctx = master->ctx;
|
||||
tls->accept = accept ? 1 : 0;
|
||||
|
||||
if (!(tls->read_buffer = malloc(tls_buffer_size)))
|
||||
free(tls), tls = NULL;
|
||||
if (!(tls->read_buffer = su_alloc(tls->home, tls_buffer_size)))
|
||||
su_home_unref(tls->home), tls = NULL;
|
||||
}
|
||||
if (!tls)
|
||||
return tls;
|
||||
@ -389,14 +388,9 @@ tls_t *tls_clone(tls_t *master, int sock, int accept)
|
||||
}
|
||||
|
||||
SSL_set_bio(tls->con, tls->bio_con, tls->bio_con);
|
||||
if (accept)
|
||||
SSL_set_accept_state(tls->con);
|
||||
else
|
||||
SSL_set_connect_state(tls->con);
|
||||
SSL_set_mode(tls->con, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
|
||||
su_setblocking(sock, 0);
|
||||
tls_read(tls); /* XXX - works only with non-blocking sockets */
|
||||
|
||||
return tls;
|
||||
}
|
||||
@ -413,24 +407,12 @@ tls_t *tls_init_client(tls_t *master, int sock)
|
||||
return tls_clone(master, sock, accept = 0);
|
||||
}
|
||||
|
||||
static char *tls_strdup(char const *s)
|
||||
{
|
||||
if (s) {
|
||||
size_t len = strlen(s) + 1;
|
||||
char *d = malloc(len);
|
||||
if (d)
|
||||
memcpy(d, s, len);
|
||||
return d;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int tls_post_connection_check(tls_t *tls)
|
||||
{
|
||||
X509 *cert;
|
||||
int extcount;
|
||||
int k, i, j, error;
|
||||
int i, j, error;
|
||||
|
||||
if (!tls) return -1;
|
||||
|
||||
@ -440,8 +422,8 @@ int tls_post_connection_check(tls_t *tls)
|
||||
|
||||
extcount = X509_get_ext_count(cert);
|
||||
|
||||
for (k = 0; k < TLS_MAX_HOSTS && tls->hosts[k]; k++)
|
||||
;
|
||||
if (!tls->subject)
|
||||
tls->subject = su_strlst_create(tls->home);
|
||||
|
||||
/* Find matching subjectAltName.DNS */
|
||||
for (i = 0; i < extcount; i++) {
|
||||
@ -464,23 +446,18 @@ int tls_post_connection_check(tls_t *tls)
|
||||
|
||||
for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
|
||||
value = sk_CONF_VALUE_value(values, j);
|
||||
if (strcmp(value->name, "DNS") == 0) {
|
||||
if (k < TLS_MAX_HOSTS) {
|
||||
tls->hosts[k] = tls_strdup(value->value);
|
||||
k += tls->hosts[k] != NULL;
|
||||
}
|
||||
}
|
||||
if (strcmp(value->name, "DNS") == 0)
|
||||
su_strlst_dup_append(tls->subject, value->value);
|
||||
else if (strcmp(value->name, "URI") == 0) {
|
||||
char const *uri = strchr(value->value, ':');
|
||||
if (uri ++ && k < TLS_MAX_HOSTS) {
|
||||
tls->hosts[k] = tls_strdup(uri);
|
||||
k += tls->hosts[k] != NULL;
|
||||
}
|
||||
char *uri = su_strlst_dup_append(tls->subject, value->value);
|
||||
char const *url = strchr(uri, ':');
|
||||
if (url++)
|
||||
su_strlst_append(tls->subject, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (k < TLS_MAX_HOSTS) {
|
||||
{
|
||||
X509_NAME *subject;
|
||||
char name[256];
|
||||
|
||||
@ -490,12 +467,12 @@ int tls_post_connection_check(tls_t *tls)
|
||||
name, sizeof name) > 0) {
|
||||
name[(sizeof name) - 1] = '\0';
|
||||
|
||||
for (i = 0; tls->hosts[i]; i++)
|
||||
if (strcasecmp(tls->hosts[i], name) == 0)
|
||||
for (i = 0; i < su_strlst_len(tls->subject); i++)
|
||||
if (strcasecmp(su_strlst_item(tls->subject, i), name) == 0)
|
||||
break;
|
||||
|
||||
if (i == k)
|
||||
tls->hosts[k++] = tls_strdup(name);
|
||||
if (i == su_strlst_len(tls->subject))
|
||||
su_strlst_dup_append(tls->subject, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -507,33 +484,13 @@ int tls_post_connection_check(tls_t *tls)
|
||||
if (error == X509_V_OK)
|
||||
tls->verified = 1;
|
||||
|
||||
if (tls->accept && !tls->verify_incoming)
|
||||
return X509_V_OK;
|
||||
else if (!tls->accept && !tls->verify_outgoing)
|
||||
return X509_V_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS])
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (tls == NULL) { errno = EINVAL; return -1; }
|
||||
if (!tls->verified) { errno = EAGAIN; return -1; }
|
||||
|
||||
if (!hosts)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hosts[i]; i++) {
|
||||
for (j = 0; tls->hosts[j]; j++) {
|
||||
if (strcasecmp(hosts[i], tls->hosts[j]) == 0)
|
||||
break;
|
||||
}
|
||||
if (tls->hosts[j] == NULL) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int tls_error(tls_t *tls, int ret, char const *who,
|
||||
void *buf, int size)
|
||||
@ -589,7 +546,7 @@ ssize_t tls_read(tls_t *tls)
|
||||
|
||||
if (0)
|
||||
SU_DEBUG_1(("tls_read(%p) called on %s (events %u)\n", (void *)tls,
|
||||
tls->type == tls_slave ? "server" : "client",
|
||||
tls->accept ? "server" : "client",
|
||||
tls->read_events));
|
||||
|
||||
if (tls->read_buffer_len)
|
||||
@ -601,19 +558,6 @@ ssize_t tls_read(tls_t *tls)
|
||||
if (ret <= 0)
|
||||
return tls_error(tls, ret, "tls_read: SSL_read", NULL, 0);
|
||||
|
||||
if (!tls->verified) {
|
||||
int err = tls_post_connection_check(tls);
|
||||
|
||||
if (err != X509_V_OK &&
|
||||
err != SSL_ERROR_SYSCALL &&
|
||||
err != SSL_ERROR_WANT_WRITE &&
|
||||
err != SSL_ERROR_WANT_READ) {
|
||||
SU_DEBUG_1((
|
||||
"%s: server certificate doesn't verify\n",
|
||||
"tls_read"));
|
||||
}
|
||||
}
|
||||
|
||||
return (ssize_t)(tls->read_buffer_len = ret);
|
||||
}
|
||||
|
||||
@ -694,13 +638,6 @@ ssize_t tls_write(tls_t *tls, void *buf, size_t size)
|
||||
|
||||
tls->write_events = 0;
|
||||
|
||||
if (!tls->verified) {
|
||||
if (tls_post_connection_check(tls) != X509_V_OK) {
|
||||
SU_DEBUG_1((
|
||||
"tls_read: server certificate doesn't verify\n"));
|
||||
}
|
||||
}
|
||||
|
||||
ret = SSL_write(tls->con, buf, size);
|
||||
if (ret < 0)
|
||||
return tls_error(tls, ret, "tls_write: SSL_write", buf, size);
|
||||
@ -748,3 +685,118 @@ int tls_events(tls_t const *tls, int mask)
|
||||
((mask & SU_WAIT_IN) ? tls->read_events : 0) |
|
||||
((mask & SU_WAIT_OUT) ? tls->write_events : 0);
|
||||
}
|
||||
|
||||
int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
|
||||
{
|
||||
tport_master_t *mr = self->tp_master;
|
||||
tport_tls_t *tlstp = (tport_tls_t *)self;
|
||||
tls_t *tls;
|
||||
int events = su_wait_events(w, self->tp_socket);
|
||||
int error;
|
||||
|
||||
SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, (void *)self,
|
||||
events & (SU_WAIT_CONNECT) ? " CONNECTING" : "",
|
||||
events & SU_WAIT_IN ? " NEGOTIATING" : "",
|
||||
events & SU_WAIT_ERR ? " ERROR" : "",
|
||||
events & SU_WAIT_HUP ? " HANGUP" : ""));
|
||||
|
||||
#if HAVE_POLL
|
||||
assert(w->fd == self->tp_socket);
|
||||
#endif
|
||||
|
||||
if (events & SU_WAIT_ERR)
|
||||
tport_error_event(self);
|
||||
|
||||
if (events & SU_WAIT_HUP && !self->tp_closed)
|
||||
tport_hup_event(self);
|
||||
|
||||
if (self->tp_closed)
|
||||
return 0;
|
||||
|
||||
error = su_soerror(self->tp_socket);
|
||||
if (error) {
|
||||
tport_error_report(self, error, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((tls = tlstp->tlstp_context) == NULL) {
|
||||
SU_DEBUG_3(("%s(%p): Error: no TLS context data for connected socket.\n",
|
||||
__func__, tlstp));
|
||||
tport_close(self);
|
||||
tport_set_secondary_timer(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->tp_is_connected == 0) {
|
||||
int ret, status;
|
||||
|
||||
ret = tls->accept ? SSL_accept(tls->con) : SSL_connect(tls->con);
|
||||
status = SSL_get_error(tls->con, ret);
|
||||
|
||||
switch (status) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
/* OpenSSL is waiting for the peer to send handshake data */
|
||||
self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP;
|
||||
su_root_eventmask(mr->mr_root, self->tp_index,
|
||||
self->tp_socket, self->tp_events);
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* OpenSSL is waiting for the peer to receive handshake data */
|
||||
self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP | SU_WAIT_OUT;
|
||||
su_root_eventmask(mr->mr_root, self->tp_index,
|
||||
self->tp_socket, self->tp_events);
|
||||
return 0;
|
||||
|
||||
case SSL_ERROR_NONE:
|
||||
/* TLS Handshake complete */
|
||||
if ( tls_post_connection_check(tls) == X509_V_OK ) {
|
||||
su_wait_t wait[1] = {SU_WAIT_INIT};
|
||||
tport_master_t *mr = self->tp_master;
|
||||
|
||||
su_root_deregister(mr->mr_root, self->tp_index);
|
||||
self->tp_index = -1;
|
||||
self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP;
|
||||
|
||||
if ((su_wait_create(wait, self->tp_socket, self->tp_events) == -1) ||
|
||||
((self->tp_index = su_root_register(mr->mr_root, wait, tport_wakeup,
|
||||
self, 0)) == -1)) {
|
||||
tport_close(self);
|
||||
tport_set_secondary_timer(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tls->read_events = SU_WAIT_IN;
|
||||
tls->write_events = 0;
|
||||
self->tp_is_connected = 1;
|
||||
self->tp_verified = tls->verified;
|
||||
self->tp_subjects = tls->subject == NULL ? NULL :
|
||||
su_strlst_dup(self->tp_home, tls->subject);
|
||||
|
||||
if (tport_has_queued(self))
|
||||
tport_send_event(self);
|
||||
else
|
||||
tport_set_secondary_timer(self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char errbuf[64];
|
||||
ERR_error_string_n(status, errbuf, 64);
|
||||
SU_DEBUG_3(("%s(%p): TLS setup failed (%s)\n",
|
||||
__func__, self, errbuf));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TLS Handshake Failed or Peer Certificate did not Verify */
|
||||
tport_close(self);
|
||||
tport_set_secondary_timer(self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include <sofia-sip/su_types.h>
|
||||
#endif
|
||||
|
||||
#include "tport_internal.h"
|
||||
|
||||
SOFIA_BEGIN_DECLS
|
||||
|
||||
#define TLS_MAX_HOSTS (16)
|
||||
@ -64,6 +66,17 @@ typedef struct tls_issues_s {
|
||||
* used, it is 0. */
|
||||
} tls_issues_t;
|
||||
|
||||
typedef struct tport_tls_s {
|
||||
tport_t tlstp_tp[1];
|
||||
tls_t *tlstp_context;
|
||||
char *tlstp_buffer;
|
||||
} tport_tls_t;
|
||||
|
||||
typedef struct tport_tls_primary_s {
|
||||
tport_primary_t tlspri_pri[1];
|
||||
tls_t *tlspri_master;
|
||||
} tport_tls_primary_t;
|
||||
|
||||
tls_t *tls_init_master(tls_issues_t *tls_issues);
|
||||
tls_t *tls_init_slave(tls_t *tls_master, int sock);
|
||||
tls_t *tls_init_client(tls_t *tls_master, int sock);
|
||||
@ -74,11 +87,10 @@ void *tls_read_buffer(tls_t *tls, size_t N);
|
||||
int tls_want_read(tls_t *tls, int events);
|
||||
int tls_pending(tls_t const *tls);
|
||||
|
||||
int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self);
|
||||
ssize_t tls_write(tls_t *tls, void *buf, size_t size);
|
||||
int tls_want_write(tls_t *tls, int events);
|
||||
|
||||
int tls_check_hosts(tls_t *tls, char const *hosts[TLS_MAX_HOSTS]);
|
||||
|
||||
int tls_events(tls_t const *tls, int flags);
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
@ -38,6 +38,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define SU_WAKEUP_ARG_T struct tport_s
|
||||
|
||||
#include "tport_internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -89,19 +91,10 @@ static int tport_tls_events(tport_t *self, int events);
|
||||
static int tport_tls_recv(tport_t *self);
|
||||
static ssize_t tport_tls_send(tport_t const *self, msg_t *msg,
|
||||
msg_iovec_t iov[], size_t iovused);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tport_primary_t tlspri_pri[1];
|
||||
tls_t *tlspri_master;
|
||||
} tport_tls_primary_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tport_t tlstp_tp[1];
|
||||
tls_t *tlstp_context;
|
||||
char *tlstp_buffer; /**< 2k Buffer */
|
||||
} tport_tls_t;
|
||||
static int tport_tls_accept(tport_primary_t *pri, int events);
|
||||
static tport_t *tport_tls_connect(tport_primary_t *pri, su_addrinfo_t *ai,
|
||||
tp_name_t const *tpn);
|
||||
static void tport_tls_deliver(tport_t *self, msg_t *msg, su_time_t now);
|
||||
|
||||
tport_vtable_t const tport_tls_vtable =
|
||||
{
|
||||
@ -109,8 +102,8 @@ tport_vtable_t const tport_tls_vtable =
|
||||
sizeof (tport_tls_primary_t),
|
||||
tport_tls_init_primary,
|
||||
tport_tls_deinit_primary,
|
||||
tport_accept,
|
||||
NULL,
|
||||
tport_tls_accept,
|
||||
tport_tls_connect,
|
||||
sizeof (tport_tls_t),
|
||||
tport_tls_init_secondary,
|
||||
tport_tls_deinit_secondary,
|
||||
@ -127,8 +120,8 @@ tport_vtable_t const tport_tls_client_vtable =
|
||||
sizeof (tport_tls_primary_t),
|
||||
tport_tls_init_client,
|
||||
tport_tls_deinit_primary,
|
||||
tport_accept,
|
||||
NULL,
|
||||
tport_tls_accept,
|
||||
tport_tls_connect,
|
||||
sizeof (tport_tls_t),
|
||||
tport_tls_init_secondary,
|
||||
tport_tls_deinit_secondary,
|
||||
@ -527,3 +520,149 @@ ssize_t tport_tls_send(tport_t const *self,
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static
|
||||
int tport_tls_accept(tport_primary_t *pri, int events)
|
||||
{
|
||||
tport_t *self;
|
||||
su_addrinfo_t ai[1];
|
||||
su_sockaddr_t su[1];
|
||||
socklen_t sulen = sizeof su;
|
||||
su_socket_t s = INVALID_SOCKET, l = pri->pri_primary->tp_socket;
|
||||
char const *reason = "accept";
|
||||
|
||||
if (events & SU_WAIT_ERR)
|
||||
tport_error_event(pri->pri_primary);
|
||||
|
||||
if (!(events & SU_WAIT_ACCEPT))
|
||||
return 0;
|
||||
|
||||
memcpy(ai, pri->pri_primary->tp_addrinfo, sizeof ai);
|
||||
ai->ai_canonname = NULL;
|
||||
|
||||
s = accept(l, &su->su_sa, &sulen);
|
||||
|
||||
if (s < 0) {
|
||||
tport_error_report(pri->pri_primary, su_errno(), NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ai->ai_addr = &su->su_sa, ai->ai_addrlen = sulen;
|
||||
|
||||
/* Alloc a new transport object, then register socket events with it */
|
||||
if ((self = tport_alloc_secondary(pri, s, 1, &reason)) == NULL) {
|
||||
SU_DEBUG_3(("%s(%p): incoming secondary on "TPN_FORMAT
|
||||
" failed. reason = %s\n", __func__, pri,
|
||||
TPN_ARGS(pri->pri_primary->tp_name), reason));
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
tport_tls_t *tlstp = (tport_tls_t *)self;
|
||||
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
|
||||
int events = SU_WAIT_IN|SU_WAIT_ERR|SU_WAIT_HUP;
|
||||
|
||||
SU_CANONIZE_SOCKADDR(su);
|
||||
|
||||
if (/* Name this transport */
|
||||
tport_setname(self, pri->pri_protoname, ai, NULL) != -1
|
||||
/* Register this secondary */
|
||||
&&
|
||||
tport_register_secondary(self, tls_connect, events) != -1) {
|
||||
|
||||
self->tp_conn_orient = 1;
|
||||
self->tp_is_connected = 0;
|
||||
|
||||
tlstp->tlstp_context = tls_init_slave(tlspri->tlspri_master, s);
|
||||
|
||||
SU_DEBUG_5(("%s(%p): new connection from " TPN_FORMAT "\n",
|
||||
__func__, (void *)self, TPN_ARGS(self->tp_name)));
|
||||
|
||||
/* Return succesfully */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Failure: shutdown socket, */
|
||||
tport_close(self);
|
||||
tport_zap_secondary(self);
|
||||
self = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
tport_t *tport_tls_connect(tport_primary_t *pri,
|
||||
su_addrinfo_t *ai,
|
||||
tp_name_t const *tpn)
|
||||
{
|
||||
tport_t *self = NULL;
|
||||
|
||||
su_socket_t s, server_socket;
|
||||
int events = SU_WAIT_CONNECT | SU_WAIT_ERR;
|
||||
|
||||
int err;
|
||||
unsigned errlevel = 3;
|
||||
char buf[TPORT_HOSTPORTSIZE];
|
||||
char const *what;
|
||||
|
||||
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (s == INVALID_SOCKET)
|
||||
goto sys_error;
|
||||
|
||||
what = "tport_alloc_secondary";
|
||||
if ((self = tport_alloc_secondary(pri, s, 0, &what)) == NULL)
|
||||
goto sys_error;
|
||||
|
||||
self->tp_conn_orient = 1;
|
||||
|
||||
if ((server_socket = pri->pri_primary->tp_socket) != INVALID_SOCKET) {
|
||||
su_sockaddr_t susa;
|
||||
socklen_t susalen = sizeof(susa);
|
||||
|
||||
if (getsockname(server_socket, &susa.su_sa, &susalen) < 0) {
|
||||
SU_DEBUG_3(("%s(%p): getsockname(): %s\n",
|
||||
__func__, (void *)self, su_strerror(su_errno())));
|
||||
} else {
|
||||
susa.su_port = 0;
|
||||
if (bind(s, &susa.su_sa, susalen) < 0) {
|
||||
SU_DEBUG_3(("%s(%p): bind(local-ip): %s\n",
|
||||
__func__, (void *)self, su_strerror(su_errno())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connect(s, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == SOCKET_ERROR) {
|
||||
err = su_errno();
|
||||
if (!su_is_blocking(err))
|
||||
goto sys_error;
|
||||
}
|
||||
|
||||
if (tport_setname(self, tpn->tpn_proto, ai, tpn->tpn_canon) != -1
|
||||
&&
|
||||
tport_register_secondary(self, tls_connect, events) != -1) {
|
||||
tport_tls_t *tlstp = (tport_tls_t *)self;
|
||||
tport_tls_primary_t *tlspri = (tport_tls_primary_t *)self->tp_pri;
|
||||
tlstp->tlstp_context = tls_init_client(tlspri->tlspri_master, s);
|
||||
}
|
||||
else
|
||||
goto sys_error;
|
||||
|
||||
SU_DEBUG_5(("%s(%p): connecting to " TPN_FORMAT "\n",
|
||||
__func__, (void *)self, TPN_ARGS(self->tp_name)));
|
||||
|
||||
tport_set_secondary_timer(self);
|
||||
|
||||
return self;
|
||||
|
||||
sys_error:
|
||||
err = errno;
|
||||
if (SU_LOG_LEVEL >= errlevel)
|
||||
su_llog(tport_log, errlevel, "%s(%p): %s (pf=%d %s/%s): %s\n",
|
||||
__func__, (void *)pri, what, ai->ai_family, tpn->tpn_proto,
|
||||
tport_hostport(buf, sizeof(buf), (void *)ai->ai_addr, 2),
|
||||
su_strerror(err));
|
||||
tport_zap_secondary(self);
|
||||
su_seterrno(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user