diff --git a/dtls.c b/dtls.c index 52c4d75..4c92a05 100644 --- a/dtls.c +++ b/dtls.c @@ -489,6 +489,7 @@ void *dtlslistener(void *arg) { ssl = SSL_new(ctx); if (!ssl) { pthread_mutex_unlock(&conf->tlsconf->lock); + debug(DBG_ERR, "dtlslistener: failed to create SSL connection"); continue; } bio = BIO_new_dgram(s, BIO_NOCLOSE); @@ -517,12 +518,27 @@ void *dtlslistener(void *arg) { } else { free(params); } + } else { + unsigned long error; + while ((error = ERR_get_error())) + debug(DBG_ERR, "dtlslistener: DTLS_listen failed: %s", ERR_error_string(error, NULL)); + debug(DBG_ERR, "dtlslistener: DTLS_listen failed from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp))); } pthread_mutex_unlock(&conf->tlsconf->lock); } return NULL; } +static void cleanup_connection(struct server *server) { + if (server->ssl) + SSL_shutdown(server->ssl); + if (server->sock >= 0) + close(server->sock); + if (server->ssl) + SSL_free(server->ssl); + server->ssl = NULL; +} + int dtlsconnect(struct server *server, int timeout, char *text) { struct timeval socktimeout, now, start; time_t wait; @@ -534,6 +550,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) { BIO *bio; struct addrinfo *source = NULL; char *subj; + struct list_node *entry; debug(DBG_DBG, "dtlsconnect: called from %s", text); pthread_mutex_lock(&server->lock); @@ -543,8 +560,6 @@ int dtlsconnect(struct server *server, int timeout, char *text) { pthread_mutex_unlock(&server->lock); - hp = (struct hostportres *)list_first(server->conf->hostports)->data; - if(server->conf->source) { source = resolvepassiveaddrinfo(server->conf->source, AF_UNSPEC, NULL, protodefs.socktype); if(!source) @@ -555,13 +570,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) { for (;;) { /* ensure previous connection is properly closed */ - if (server->ssl) - SSL_shutdown(server->ssl); - if (server->sock >= 0) - close(server->sock); - if (server->ssl) - SSL_free(server->ssl); - server->ssl = NULL; + cleanup_connection(server); wait = connect_wait(start, server->connecttime, firsttry); gettimeofday(&now, NULL); @@ -570,55 +579,74 @@ int dtlsconnect(struct server *server, int timeout, char *text) { if (source) freeaddrinfo(source); return 0; } - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); sleep(wait); firsttry = 0; - debug(DBG_INFO, "dtlsconnect: connecting to %s port %s", hp->host, hp->port); + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) { + hp = (struct hostportres *)entry->data; + debug(DBG_INFO, "dtlsconnect: trying to open DTLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port); + if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0) { + debug(DBG_ERR, "dtlsconnect: faild to bind socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port); + goto concleanup; + } + if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen)) { + debug(DBG_ERR, "dtlsconnect: faild to connect socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port); + goto concleanup; + } - if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0) - continue; - if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen)) - continue; + pthread_mutex_lock(&server->conf->tlsconf->lock); + if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){ + pthread_mutex_unlock(&server->conf->tlsconf->lock); + debug(DBG_ERR, "dtlsconnect: failed to get TLS context for server %s", server->conf->name); + goto concleanup; + } - pthread_mutex_lock(&server->conf->tlsconf->lock); - if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){ + server->ssl = SSL_new(ctx); pthread_mutex_unlock(&server->conf->tlsconf->lock); - continue; - } - - server->ssl = SSL_new(ctx); - pthread_mutex_unlock(&server->conf->tlsconf->lock); - if (!server->ssl) - continue; + if (!server->ssl) { + debug(DBG_ERR, "dtlsconnect: failed to create SSL conneciton for server %s", server->conf->name); + goto concleanup; + } - bio = BIO_new_dgram(server->sock, BIO_CLOSE); - BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr); - SSL_set_bio(server->ssl, bio, bio); - if (sslconnecttimeout(server->ssl, 5) <= 0) { - while ((error = ERR_get_error())) - debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL)); - debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed", server->conf->name); - continue; - } - socktimeout.tv_sec = 5; - socktimeout.tv_usec = 0; - if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1) - debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed"); + bio = BIO_new_dgram(server->sock, BIO_CLOSE); + BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr); + SSL_set_bio(server->ssl, bio, bio); + if (sslconnecttimeout(server->ssl, 5) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL)); + debug(DBG_ERR, "dtlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port); + goto concleanup; + } + socktimeout.tv_sec = 5; + socktimeout.tv_usec = 0; + if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1) + debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed"); + + cert = verifytlscert(server->ssl); + if (!cert) { + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port); + goto concleanup; + } - cert = verifytlscert(server->ssl); - if (!cert) - continue; - if (verifyconfcert(cert, server->conf, hp)) { - subj = getcertsubject(cert); - if(subj) { - debug(DBG_WARN, "dtlsconnect: DTLS connection to %s, subject %s up", server->conf->name, subj); - free(subj); + if (verifyconfcert(cert, server->conf, hp)) { + subj = getcertsubject(cert); + if(subj) { + debug(DBG_WARN, "dtlsconnect: DTLS connection to %s (%s port %s), subject %s up", server->conf->name, hp->host, hp->port, subj); + free(subj); + } + X509_free(cert); + break; + } else { + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port); } X509_free(cert); - break; + +concleanup: + /* ensure previous connection is properly closed */ + cleanup_connection(server); } - X509_free(cert); + if (server->ssl) break; } pthread_mutex_lock(&server->lock); diff --git a/tcp.c b/tcp.c index 5336435..e148ed0 100644 --- a/tcp.c +++ b/tcp.c @@ -22,6 +22,7 @@ #include #include "radsecproxy.h" #include "hostport.h" +#include "list.h" #ifdef RADPROT_TCP #include "debug.h" @@ -84,6 +85,8 @@ int tcpconnect(struct server *server, int timeout, char *text) { int firsttry = 1; time_t wait; struct addrinfo *source = NULL; + struct list_node *entry; + struct hostportres *hp; debug(DBG_DBG, "tcpconnect: called from %s", text); pthread_mutex_lock(&server->lock); @@ -112,16 +115,25 @@ int tcpconnect(struct server *server, int timeout, char *text) { if (source) freeaddrinfo(source); return 0; } - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); sleep(wait); firsttry = 0; - pthread_mutex_lock(&server->lock); - debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name); - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, NULL)) < 0) + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) { + hp = (struct hostportres *)entry->data; + debug(DBG_INFO, "tcpconnect: trying to open TCP connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port); + if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) >= 0) { + debug(DBG_WARN, "tcpconnect: TCP connection to server %s (%s port %s) up", hp->host, hp->port); + break; + } + } + if (server->sock < 0) { + debug(DBG_ERR, "tcpconnect: TCP connection to server %s failed", server->conf->name); continue; + } + if (server->conf->keepalive) enable_keepalive(server->sock); break; diff --git a/tls.c b/tls.c index 76a97bd..46088cc 100644 --- a/tls.c +++ b/tls.c @@ -23,11 +23,11 @@ #include #include "radsecproxy.h" #include "hostport.h" - -#ifdef RADPROT_TLS #include "debug.h" #include "util.h" +#ifdef RADPROT_TLS + static void setprotoopts(struct commonprotoopts *opts); static char **getlistenerargs(); void *tlslistener(void *arg); @@ -82,6 +82,16 @@ void tlssetsrcres() { AF_UNSPEC, NULL, protodefs.socktype); } +static void cleanup_connection(struct server *server) { + if (server->ssl) + SSL_shutdown(server->ssl); + if (server->sock >= 0) + close(server->sock); + if (server->ssl) + SSL_free(server->ssl); + server->ssl = NULL; +} + int tlsconnect(struct server *server, int timeout, char *text) { struct timeval now, start; time_t wait; @@ -92,7 +102,8 @@ int tlsconnect(struct server *server, int timeout, char *text) { int origflags; struct addrinfo *source = NULL; char *subj; - struct hostportres *hpconnected = NULL; + struct list_node *entry; + struct hostportres *hp; debug(DBG_DBG, "tlsconnect: called from %s", text); pthread_mutex_lock(&server->lock); @@ -109,15 +120,7 @@ int tlsconnect(struct server *server, int timeout, char *text) { gettimeofday(&start, NULL); for (;;) { - /* ensure previous connection is properly closed */ - if (server->ssl) - SSL_shutdown(server->ssl); - if (server->sock >= 0) - close(server->sock); - if (server->ssl) - SSL_free(server->ssl); - server->ssl = NULL; - + cleanup_connection(server); wait = connect_wait(start, server->connecttime, firsttry); gettimeofday(&now, NULL); if (timeout && (now.tv_sec - start.tv_sec) + wait > timeout) { @@ -125,7 +128,7 @@ int tlsconnect(struct server *server, int timeout, char *text) { if (source) freeaddrinfo(source); return 0; } - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); sleep(wait); firsttry = 0; @@ -136,46 +139,64 @@ int tlsconnect(struct server *server, int timeout, char *text) { return 0; } - debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name); - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, &hpconnected)) < 0) - continue; - if (server->conf->keepalive) - enable_keepalive(server->sock); + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) { + hp = (struct hostportres *)entry->data; + debug(DBG_INFO, "tlsconnect: trying to open TLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port); + if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) < 0 ) { + debug(DBG_ERR, "tlsconnect: TLS connection to %s (%s port %s) failed: TCP connect failed", server->conf->name, hp->host, hp->port); + goto concleanup; + } - pthread_mutex_lock(&server->conf->tlsconf->lock); - if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){ - pthread_mutex_unlock(&server->conf->tlsconf->lock); - continue; - } + if (server->conf->keepalive) + enable_keepalive(server->sock); - server->ssl = SSL_new(ctx); - pthread_mutex_unlock(&server->conf->tlsconf->lock); - if (!server->ssl) - continue; + pthread_mutex_lock(&server->conf->tlsconf->lock); + if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))) { + pthread_mutex_unlock(&server->conf->tlsconf->lock); + debug(DBG_ERR, "tlsconnect: failed to get TLS context for server %s", server->conf->name); + goto concleanup; + } - SSL_set_fd(server->ssl, server->sock); - if (sslconnecttimeout(server->ssl, 5) <= 0) { - while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL)); - debug(DBG_ERR, "tlsconnect: SSL connect to %s failed", server->conf->name); - continue; - } + server->ssl = SSL_new(ctx); + pthread_mutex_unlock(&server->conf->tlsconf->lock); + if (!server->ssl) { + debug(DBG_ERR, "tlsconnect: failed to create SSL conneciton for server %s", server->conf->name); + goto concleanup; + } + + SSL_set_fd(server->ssl, server->sock); + if (sslconnecttimeout(server->ssl, 5) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL)); + debug(DBG_ERR, "tlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port); + goto concleanup; + } - cert = verifytlscert(server->ssl); - if (!cert) - continue; - if (verifyconfcert(cert, server->conf, hpconnected)) { - subj = getcertsubject(cert); - if(subj) { - debug(DBG_WARN, "tlsconnect: TLS connection to %s, subject %s up", server->conf->name, subj); - free(subj); + cert = verifytlscert(server->ssl); + if (!cert) { + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port); + goto concleanup; + } + + if (verifyconfcert(cert, server->conf, hp)) { + subj = getcertsubject(cert); + if(subj) { + debug(DBG_WARN, "tlsconnect: TLS connection to %s (%s port %s), subject %s up", server->conf->name, hp->host, hp->port, subj); + free(subj); + } + X509_free(cert); + break; + } else { + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port); } X509_free(cert); - break; + +concleanup: + /* ensure previous connection is properly closed */ + cleanup_connection(server); } - X509_free(cert); + if (server->ssl) break; } - debug(DBG_WARN, "tlsconnect: TLS connection to %s up", server->conf->name); origflags = fcntl(server->sock, F_GETFL, 0); if (origflags == -1) {