summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--radsecproxy.c607
-rw-r--r--radsecproxy.h11
2 files changed, 455 insertions, 163 deletions
diff --git a/radsecproxy.c b/radsecproxy.c
index c4d0639..90a2914 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -70,7 +70,7 @@ struct list *clconfs, *srvconfs, *realms, *tlsconfs, *rewriteconfs;
static struct addrinfo *srcprotores[3] = { NULL, NULL, NULL };
-static struct replyq *udp_server_replyq = NULL;
+static struct queue *udp_server_replyq = NULL;
static int udp_client4_sock = -1;
static int udp_client6_sock = -1;
static pthread_mutex_t tlsconfs_lock;
@@ -90,7 +90,8 @@ void *udpserverrd(void *arg);
void *tlslistener(void *arg);
void *tcplistener(void *arg);
int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text);
-int dtlsinitserver(struct server *server, struct timeval *when, int timeout, char *text);
+int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text);
+void *dtlsservernew(void *arg);
int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text);
void *udpclientrd(void *arg);
void *tlsclientrd(void *arg);
@@ -100,7 +101,9 @@ int clientradputudp(struct server *server, unsigned char *rad);
int clientradputtls(struct server *server, unsigned char *rad);
int clientradputdtls(struct server *server, unsigned char *rad);
int clientradputtcp(struct server *server, unsigned char *rad);
-
+X509 *verifytlscert(SSL *ssl);
+int radsrv(struct request *rq);
+
static const struct protodefs protodefs[] = {
{ "udp", /* UDP, assuming RAD_UDP defined as 0 */
NULL, /* secretdefault */
@@ -154,7 +157,7 @@ static const struct protodefs protodefs[] = {
60, /* retryintervalmax */
NULL, /* listener */
&options.sourceudp, /* srcaddrport */
- dtlsinitserver, /* connecter */
+ dtlsconnect, /* connecter */
dtlsclientrd, /* clientreader */
clientradputdtls /* clientradput */
},
@@ -500,18 +503,40 @@ struct clsrvconf *find_conf_type(uint8_t type, struct list *confs, struct list_n
return NULL;
}
-struct replyq *newreplyq() {
- struct replyq *replyq;
+struct queue *newqueue() {
+ struct queue *q;
- replyq = malloc(sizeof(struct replyq));
- if (!replyq)
+ q = malloc(sizeof(struct queue));
+ if (!q)
debugx(1, DBG_ERR, "malloc failed");
- replyq->replies = list_create();
- if (!replyq->replies)
+ q->entries = list_create();
+ if (!q->entries)
debugx(1, DBG_ERR, "malloc failed");
- pthread_mutex_init(&replyq->mutex, NULL);
- pthread_cond_init(&replyq->cond, NULL);
- return replyq;
+ pthread_mutex_init(&q->mutex, NULL);
+ pthread_cond_init(&q->cond, NULL);
+ return q;
+}
+
+void removequeue(struct queue *q) {
+ struct list_node *entry;
+
+ pthread_mutex_lock(&q->mutex);
+ for (entry = list_first(q->entries); entry; entry = list_next(entry))
+ free(((struct reply *)entry)->buf);
+ list_destroy(q->entries);
+ pthread_cond_destroy(&q->cond);
+ pthread_mutex_unlock(&q->mutex);
+ pthread_mutex_destroy(&q->mutex);
+}
+
+void freebios(struct queue *q) {
+ BIO *bio;
+
+ pthread_mutex_lock(&q->mutex);
+ while ((bio = (BIO *)list_shift(q->entries)))
+ BIO_free(bio);
+ pthread_mutex_unlock(&q->mutex);
+ removequeue(q);
}
struct client *addclient(struct clsrvconf *conf) {
@@ -531,25 +556,19 @@ struct client *addclient(struct clsrvconf *conf) {
memset(new, 0, sizeof(struct client));
new->conf = conf;
- new->replyq = conf->type == RAD_UDP || conf->type == RAD_DTLS ? udp_server_replyq : newreplyq();
-
+ new->replyq = conf->type == RAD_UDP ? udp_server_replyq : newqueue();
+ if (conf->type == RAD_DTLS)
+ new->rbios = newqueue();
list_push(conf->clients, new);
return new;
}
void removeclient(struct client *client) {
- struct list_node *entry;
-
if (!client || !client->conf->clients)
return;
-
- pthread_mutex_lock(&client->replyq->mutex);
- for (entry = list_first(client->replyq->replies); entry; entry = list_next(entry))
- free(((struct reply *)entry)->buf);
- list_destroy(client->replyq->replies);
- pthread_cond_destroy(&client->replyq->cond);
- pthread_mutex_unlock(&client->replyq->mutex);
- pthread_mutex_destroy(&client->replyq->mutex);
+ removequeue(client->replyq);
+ if (client->rbios)
+ freebios(client->rbios);
list_removedata(client->conf->clients, client);
free(client);
}
@@ -580,12 +599,14 @@ void freeserver(struct server *server, uint8_t destroymutex) {
if (!server)
return;
- if(server->requests) {
+ if (server->requests) {
rq = server->requests;
for (end = rq + MAX_REQUESTS; rq < end; rq++)
freerqdata(rq);
free(server->requests);
}
+ if (server->rbios)
+ freebios(server->rbios);
free(server->dynamiclookuparg);
if (destroymutex) {
pthread_mutex_destroy(&server->lock);
@@ -612,8 +633,10 @@ int addserver(struct clsrvconf *conf) {
conf->servers->conf = conf;
type = conf->type;
- if (type == RAD_DTLS)
+ if (type == RAD_DTLS) {
+ conf->servers->rbios = newqueue();
type = RAD_UDP;
+ }
if (!srcprotores[type]) {
res = resolve_hostport(type, *conf->pdef->srcaddrport, NULL);
@@ -677,77 +700,40 @@ int addserver(struct clsrvconf *conf) {
return 0;
}
-unsigned char *dtlsread(int s, struct clsrvconf *conf, SSL *ssl, int cnt, struct sockaddr *peer) {
- unsigned char sslbuf[65536], *buf;
- int sslbuflen = 65536, len;
- BIO *rbio, *tmpbio;
- BIO *dummybio, *wbio;
- unsigned long error;
+int udp2bio(int s, struct queue *q, int cnt) {
+ unsigned char *buf;
+ BIO *rbio;
+
+ if (cnt < 1)
+ return 0;
buf = malloc(cnt);
if (!buf) {
- debug(DBG_ERR, "dtlsread: malloc failed");
- recv(s, sslbuf, 4, 0);
- return NULL;
+ debug(DBG_ERR, "udp2bio: malloc failed");
+ /* is this ok? */
+ recv(s, NULL, 0, 0);
+ return 0;
}
cnt = recv(s, buf, cnt, 0);
- if (cnt == -1) {
- debug(DBG_WARN, "dtlsread: recv failed");
+ if (cnt < 1) {
+ debug(DBG_WARN, "udp2bio: recv failed");
free(buf);
- return NULL;
+ return 0;
}
- dummybio = BIO_new(BIO_s_mem());
- /* trying to read from this BIO always returns retry */
- BIO_set_mem_eof_return(dummybio, -1);
- wbio = BIO_new_dgram(s, BIO_NOCLOSE);
-
- if (peer)
- BIO_dgram_set_peer(wbio, peer);
- /* the real rbio will be set by radudpget */
- SSL_set_bio(ssl, dummybio, wbio);
- SSL_set_accept_state(ssl);
-
rbio = BIO_new_mem_buf(buf, cnt);
BIO_set_mem_eof_return(rbio, -1);
-
- tmpbio = ssl->rbio;
- ssl->rbio = rbio;
- cnt = SSL_read(ssl, sslbuf, sslbuflen);
- debug(DBG_INFO, "dtlsread: DTLS: got %d bytes", cnt);
-
- error = SSL_get_error(ssl, cnt);
- ssl->rbio = tmpbio;
- BIO_free(ssl->rbio);
- free(buf);
-
- if (cnt < 0) {
- debug(DBG_ERR, "dtlsread: DTLS: %s", ERR_error_string(error, NULL));
- if (error == SSL_ERROR_ZERO_RETURN) {
- /* remove ssl state? */
- }
- while ((error = ERR_get_error()))
- debug(DBG_ERR, "dtlsread: DTLS: %s", ERR_error_string(error, NULL));
- return NULL;
- }
- len = RADLEN(sslbuf);
- if (cnt < len) {
- debug(DBG_WARN, "dtlsread: packet smaller than length field in radius header");
- return NULL;
- }
- if (cnt > len)
- debug(DBG_DBG, "dtlsread: packet was padded with %d bytes", cnt - len);
-
- buf = malloc(cnt);
- if (!buf) {
- debug(DBG_ERR, "dtlsread: malloc failed");
- return NULL;
+ pthread_mutex_lock(&q->mutex);
+ if (!list_push(q->entries, rbio)) {
+ BIO_free(rbio);
+ pthread_mutex_unlock(&q->mutex);
+ return 0;
}
-
- memcpy(buf, sslbuf, len);
- return buf;
+ pthread_cond_signal(&q->cond);
+ pthread_mutex_unlock(&q->mutex);
+ return 1;
}
/* exactly one of client and server must be non-NULL */
@@ -761,6 +747,7 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,
struct clsrvconf *p;
struct list_node *node;
fd_set readfds;
+ pthread_t dtlsserverth;
for (;;) {
if (rad) {
@@ -776,10 +763,11 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,
debug(DBG_WARN, "radudpget: recv failed");
continue;
}
-
+
if ((p = find_conf(RAD_UDP, (struct sockaddr *)&from, client ? clconfs : srvconfs, NULL))) {
- len = RADLEN(buf);
- if (len < 20) {
+ if (cnt >= 20)
+ len = RADLEN(buf);
+ if (cnt < 20 || len < 20) {
debug(DBG_WARN, "radudpget: length too small");
recv(s, buf, 4, 0);
continue;
@@ -813,19 +801,42 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,
if (client) {
node = list_first(p->clients);
- *client = node ? (struct client *)node->data : addclient(p);
- if (!*client)
- continue;
- if (p->type == RAD_DTLS) {
- if (!(*client)->ssl)
- (*client)->ssl = SSL_new(p->ssl_ctx);
- rad = dtlsread(s, p, (*client)->ssl, cnt, (struct sockaddr *)&from);
- if (!rad)
+ switch (p->type) {
+ case RAD_UDP:
+ *client = node ? (struct client *)node->data : addclient(p);
+ if (!*client)
continue;
- debug(DBG_DBG, "radudpget: got DTLS message from %s", cnt, addr2string((struct sockaddr *)&from, fromlen));
+ break;
+ case RAD_DTLS:
+ if (node)
+ *client = (struct client *)node->data;
+ else {
+ *client = addclient(p);
+ if (!*client)
+ continue;
+ (*client)->sock = s;
+ memcpy(&(*client)->addr, &from, fromlen);
+ if (pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)*client)) {
+ debug(DBG_ERR, "radudpget: pthread_create failed");
+ removeclient(*client);
+ continue;
+ }
+ pthread_detach(dtlsserverth);
+ }
+ if (udp2bio(s, (*client)->rbios, cnt))
+ debug(DBG_DBG, "radudpget: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen));
+ continue;
+ default:
+ continue;
}
- } else if (server)
+ } else if (server) {
*server = p->servers;
+ if (p->type == RAD_DTLS) {
+ if (udp2bio(s, (*server)->rbios, cnt))
+ debug(DBG_DBG, "radudpget: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen));
+ continue;
+ }
+ }
break;
}
if (sa)
@@ -1092,24 +1103,293 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t
return 1;
}
-int dtlsinitserver(struct server *server, struct timeval *when, int timeout, char *text) {
- BIO *dummybio, *wbio;
+void *dtlsserverwr(void *arg) {
+ int cnt;
+ unsigned long error;
+ struct client *client = (struct client *)arg;
+ struct queue *replyq;
+ struct reply *reply;
+
+ debug(DBG_DBG, "dtlsserverwr: starting for %s", client->conf->host);
+ replyq = client->replyq;
+ for (;;) {
+ pthread_mutex_lock(&replyq->mutex);
+ while (!list_first(replyq->entries)) {
+ if (client->ssl) {
+ debug(DBG_DBG, "dtlsserverwr: waiting for signal");
+ pthread_cond_wait(&replyq->cond, &replyq->mutex);
+ debug(DBG_DBG, "dtlsserverwr: got signal");
+ }
+ if (!client->ssl) {
+ /* ssl might have changed while waiting */
+ pthread_mutex_unlock(&replyq->mutex);
+ debug(DBG_DBG, "dtlsserverwr: exiting as requested");
+ ERR_remove_state(0);
+ pthread_exit(NULL);
+ }
+ }
+ reply = (struct reply *)list_shift(replyq->entries);
+ pthread_mutex_unlock(&replyq->mutex);
+ cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf));
+ if (cnt > 0)
+ debug(DBG_DBG, "dtlsserverwr: sent %d bytes, Radius packet of length %d",
+ cnt, RADLEN(reply->buf));
+ else
+ while ((error = ERR_get_error()))
+ debug(DBG_ERR, "dtlsserverwr: SSL: %s", ERR_error_string(error, NULL));
+ free(reply->buf);
+ free(reply);
+ }
+}
+
+BIO *getrbio(SSL *ssl, struct queue *q, int timeout) {
+ BIO *rbio;
+ struct timeval now;
+ struct timespec to;
+
+ pthread_mutex_lock(&q->mutex);
+ if (!(rbio = (BIO *)list_shift(q->entries))) {
+ if (timeout) {
+ gettimeofday(&now, NULL);
+ memset(&to, 0, sizeof(struct timespec));
+ to.tv_sec = now.tv_sec + timeout;
+ pthread_cond_timedwait(&q->cond, &q->mutex, &to);
+ } else
+ pthread_cond_wait(&q->cond, &q->mutex);
+ rbio = (BIO *)list_shift(q->entries);
+ }
+ pthread_mutex_unlock(&q->mutex);
+ return rbio;
+}
+
+int dtlsread(SSL *ssl, struct queue *q, unsigned char *buf, int num) {
+ int len, cnt;
+
+ for (len = 0; len < num; len += cnt) {
+ cnt = SSL_read(ssl, buf + len, num - len);
+ if (cnt <= 0)
+ switch (cnt = SSL_get_error(ssl, cnt)) {
+ case SSL_ERROR_WANT_READ:
+ BIO_free(ssl->rbio);
+ ssl->rbio = getrbio(ssl, q, 0);
+ if (!ssl->rbio)
+ return -1;
+ cnt = 0;
+ continue;
+ case SSL_ERROR_WANT_WRITE:
+ cnt = 0;
+ continue;
+ case SSL_ERROR_ZERO_RETURN:
+ /* remote end sent close_notify, send one back */
+ SSL_shutdown(ssl);
+ return -1;
+ default:
+ return -1;
+ }
+ }
+ return num;
+}
+
+unsigned char *raddtlsget(SSL *ssl, struct queue *rbios) {
+ int cnt, len;
+ unsigned char buf[4], *rad;
+
+ for (;;) {
+ cnt = dtlsread(ssl, rbios, buf, 4);
+ if (cnt < 1) {
+ debug(DBG_DBG, "raddtlsget: connection lost");
+ return NULL;
+ }
+
+ len = RADLEN(buf);
+ rad = malloc(len);
+ if (!rad) {
+ debug(DBG_ERR, "raddtlsget: malloc failed");
+ continue;
+ }
+ memcpy(rad, buf, 4);
+
+ cnt = dtlsread(ssl, rbios, rad + 4, len - 4);
+ if (cnt < 1) {
+ debug(DBG_DBG, "raddtlsget: connection lost");
+ free(rad);
+ return NULL;
+ }
+
+ if (len >= 20)
+ break;
+
+ free(rad);
+ debug(DBG_WARN, "raddtlsget: packet smaller than minimum radius size");
+ }
- debug(DBG_DBG, "dtlsinitserver: called from %s", text);
- server->ssl = SSL_new(server->conf->ssl_ctx);
- SSL_set_connect_state(server->ssl);
+ debug(DBG_DBG, "raddtlsget: got %d bytes", len);
+ return rad;
+}
+
+void dtlsserverrd(struct client *client) {
+ struct request rq;
+ pthread_t dtlsserverwrth;
- dummybio = BIO_new(BIO_s_mem());
- /* trying to read from this BIO always returns retry */
- BIO_set_mem_eof_return(dummybio, -1);
- wbio = BIO_new_dgram(server->sock, BIO_NOCLOSE);
- BIO_dgram_set_peer(wbio, server->conf->addrinfo->ai_addr);
- /* the real rbio will be set by radudpget */
- SSL_set_bio(server->ssl, dummybio, wbio);
+ debug(DBG_DBG, "dtlsserverrd: starting for %s", client->conf->host);
- return 1;
+ if (pthread_create(&dtlsserverwrth, NULL, dtlsserverwr, (void *)client)) {
+ debug(DBG_ERR, "dtlsserverrd: pthread_create failed");
+ return;
+ }
+
+ for (;;) {
+ memset(&rq, 0, sizeof(struct request));
+ rq.buf = raddtlsget(client->ssl, client->rbios);
+ if (!rq.buf) {
+ debug(DBG_ERR, "dtlsserverrd: connection from %s lost", client->conf->host);
+ break;
+ }
+ debug(DBG_DBG, "dtlsserverrd: got Radius message from %s", client->conf->host);
+ rq.from = client;
+ if (!radsrv(&rq)) {
+ debug(DBG_ERR, "dtlsserverrd: message authentication/validation failed, closing connection from %s", client->conf->host);
+ break;
+ }
+ }
+
+ /* stop writer by setting ssl to NULL and give signal in case waiting for data */
+ client->ssl = NULL;
+
+ pthread_mutex_lock(&client->replyq->mutex);
+ pthread_cond_signal(&client->replyq->cond);
+ pthread_mutex_unlock(&client->replyq->mutex);
+ debug(DBG_DBG, "dtlsserverrd: waiting for writer to end");
+ pthread_join(dtlsserverwrth, NULL);
+ removeclientrqs(client);
+ debug(DBG_DBG, "dtlsserverrd: reader for %s exiting", client->conf->host);
+}
+
+/* accept if acc == 1, else connect */
+SSL *dtlsacccon(uint8_t acc, SSL_CTX *ctx, int s, struct sockaddr *addr, struct queue *rbios) {
+ SSL *ssl;
+ int i, res;
+ unsigned long error;
+ BIO *mem0bio, *wbio;
+
+ ssl = SSL_new(ctx);
+ if (!ssl)
+ return NULL;
+
+ mem0bio = BIO_new(BIO_s_mem());
+ BIO_set_mem_eof_return(mem0bio, -1);
+ wbio = BIO_new_dgram(s, BIO_NOCLOSE);
+ BIO_dgram_set_peer(wbio, addr);
+ SSL_set_bio(ssl, mem0bio, wbio);
+
+ for (i = 0; i < 5; i++) {
+ res = acc ? SSL_accept(ssl) : SSL_connect(ssl);
+ if (res > 0)
+ return ssl;
+ if (res == 0)
+ break;
+ if (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ) {
+ BIO_free(ssl->rbio);
+ ssl->rbio = getrbio(ssl, rbios, 5);
+ if (!ssl->rbio)
+ break;
+ }
+ while ((error = ERR_get_error()))
+ debug(DBG_ERR, "dtls%st: DTLS: %s", acc ? "accep" : "connec", ERR_error_string(error, NULL));
+ }
+
+ SSL_free(ssl);
+ return NULL;
+}
+
+void *dtlsservernew(void *arg) {
+ struct client *client = (struct client *)arg;
+ X509 *cert = NULL;
+
+ client->ssl = dtlsacccon(1, client->conf->ssl_ctx, client->sock, (struct sockaddr *)&client->addr, client->rbios);
+ if (!client->ssl)
+ goto exit;
+ cert = verifytlscert(client->ssl);
+ if (!cert)
+ goto exit;
+ if (verifyconfcert(cert, client->conf)) {
+ X509_free(cert);
+ dtlsserverrd(client);
+ removeclient(client);
+ } else
+ debug(DBG_WARN, "dtlsservernew: ignoring request, certificate validation failed");
+ if (cert)
+ X509_free(cert);
+
+ exit:
+ SSL_free(client->ssl);
+ ERR_remove_state(0);
+ pthread_exit(NULL);
}
+
+int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
+ struct timeval now;
+ time_t elapsed;
+ X509 *cert;
+ debug(DBG_DBG, "dtlsconnect: called from %s", text);
+ pthread_mutex_lock(&server->lock);
+ if (when && memcmp(&server->lastconnecttry, when, sizeof(struct timeval))) {
+ /* already reconnected, nothing to do */
+ debug(DBG_DBG, "dtlsconnect(%s): seems already reconnected", text);
+ pthread_mutex_unlock(&server->lock);
+ return 1;
+ }
+
+ for (;;) {
+ gettimeofday(&now, NULL);
+ elapsed = now.tv_sec - server->lastconnecttry.tv_sec;
+
+ if (timeout && server->lastconnecttry.tv_sec && elapsed > timeout) {
+ debug(DBG_DBG, "dtlsconnect: timeout");
+ SSL_free(server->ssl);
+ server->ssl = NULL;
+ pthread_mutex_unlock(&server->lock);
+ return 0;
+ }
+
+ if (server->connectionok) {
+ server->connectionok = 0;
+ sleep(2);
+ } else if (elapsed < 1)
+ sleep(2);
+ else if (elapsed < 60) {
+ debug(DBG_INFO, "dtlsconnect: sleeping %lds", elapsed);
+ sleep(elapsed);
+ } else if (elapsed < 100000) {
+ debug(DBG_INFO, "dtlsconnect: sleeping %ds", 60);
+ sleep(60);
+ } else
+ server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */
+ debug(DBG_WARN, "dtlsconnect: trying to open DTLS connection to %s port %s", server->conf->host, server->conf->port);
+
+ SSL_free(server->ssl);
+ server->ssl = dtlsacccon(0, server->conf->ssl_ctx, server->sock, server->conf->addrinfo->ai_addr, server->rbios);
+ if (!server->ssl)
+ continue;
+ debug(DBG_DBG, "dtlsconnect: DTLS: ok");
+
+ cert = verifytlscert(server->ssl);
+ if (!cert)
+ continue;
+
+ if (verifyconfcert(cert, server->conf)) {
+ X509_free(cert);
+ break;
+ }
+ X509_free(cert);
+ }
+ debug(DBG_WARN, "dtlsconnect: DTLS connection to %s port %s up", server->conf->host, server->conf->port);
+ gettimeofday(&server->lastconnecttry, NULL);
+ pthread_mutex_unlock(&server->lock);
+ return 1;
+}
+
int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text) {
struct timeval now;
time_t elapsed;
@@ -1192,7 +1472,7 @@ int sslreadtimeout(SSL *ssl, unsigned char *buf, int num, int timeout) {
case SSL_ERROR_ZERO_RETURN:
/* remote end sent close_notify, send one back */
SSL_shutdown(ssl);
- /* fall through */
+ return -1;
default:
return -1;
}
@@ -1606,9 +1886,9 @@ void sendreply(struct client *to, unsigned char *buf, struct sockaddr_storage *t
pthread_mutex_lock(&to->replyq->mutex);
- first = list_first(to->replyq->replies) == NULL;
+ first = list_first(to->replyq->entries) == NULL;
- if (!list_push(to->replyq->replies, reply)) {
+ if (!list_push(to->replyq->entries, reply)) {
pthread_mutex_unlock(&to->replyq->mutex);
free(reply);
free(buf);
@@ -2659,13 +2939,21 @@ void *tlsclientrd(void *arg) {
void *dtlsclientrd(void *arg) {
struct server *server = (struct server *)arg;
+ unsigned char *buf;
+ struct timeval lastconnecttry;
for (;;) {
- sleep(1000);
+ /* yes, lastconnecttry is really necessary */
+ lastconnecttry = server->lastconnecttry;
+ buf = raddtlsget(server->ssl, server->rbios);
+ if (!buf) {
+ dtlsconnect(server, &lastconnecttry, 0, "dtlsclientrd");
+ continue;
+ }
+
+ if (!replyh(server, buf))
+ free(buf);
}
- ERR_remove_state(0);
- server->clientrdgone = 1;
- return NULL;
}
void *tcpclientrd(void *arg) {
@@ -2862,12 +3150,12 @@ void *clientwr(void *arg) {
}
void *udpserverwr(void *arg) {
- struct replyq *replyq = udp_server_replyq;
+ struct queue *replyq = udp_server_replyq;
struct reply *reply;
for (;;) {
pthread_mutex_lock(&replyq->mutex);
- while (!(reply = (struct reply *)list_shift(replyq->replies))) {
+ while (!(reply = (struct reply *)list_shift(replyq->entries))) {
debug(DBG_DBG, "udp server writer, waiting for signal");
pthread_cond_wait(&replyq->cond, &replyq->mutex);
debug(DBG_DBG, "udp server writer, got signal");
@@ -2899,14 +3187,14 @@ void *tlsserverwr(void *arg) {
int cnt;
unsigned long error;
struct client *client = (struct client *)arg;
- struct replyq *replyq;
+ struct queue *replyq;
struct reply *reply;
debug(DBG_DBG, "tlsserverwr: starting for %s", client->conf->host);
replyq = client->replyq;
for (;;) {
pthread_mutex_lock(&replyq->mutex);
- while (!list_first(replyq->replies)) {
+ while (!list_first(replyq->entries)) {
if (client->ssl) {
debug(DBG_DBG, "tlsserverwr: waiting for signal");
pthread_cond_wait(&replyq->cond, &replyq->mutex);
@@ -2920,7 +3208,7 @@ void *tlsserverwr(void *arg) {
pthread_exit(NULL);
}
}
- reply = (struct reply *)list_shift(replyq->replies);
+ reply = (struct reply *)list_shift(replyq->entries);
pthread_mutex_unlock(&replyq->mutex);
cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf));
if (cnt > 0)
@@ -3060,29 +3348,29 @@ void *tlslistener(void *arg) {
void *tcpserverwr(void *arg) {
int cnt;
struct client *client = (struct client *)arg;
- struct replyq *replyq;
+ struct queue *replyq;
struct reply *reply;
debug(DBG_DBG, "tcpserverwr: starting for %s", client->conf->host);
replyq = client->replyq;
for (;;) {
pthread_mutex_lock(&replyq->mutex);
- while (!list_first(replyq->replies)) {
- if (client->s >= 0) {
+ while (!list_first(replyq->entries)) {
+ if (client->sock >= 0) {
debug(DBG_DBG, "tcpserverwr: waiting for signal");
pthread_cond_wait(&replyq->cond, &replyq->mutex);
debug(DBG_DBG, "tcpserverwr: got signal");
}
- if (client->s < 0) {
+ if (client->sock < 0) {
/* s might have changed while waiting */
pthread_mutex_unlock(&replyq->mutex);
debug(DBG_DBG, "tcpserverwr: exiting as requested");
pthread_exit(NULL);
}
}
- reply = (struct reply *)list_shift(replyq->replies);
+ reply = (struct reply *)list_shift(replyq->entries);
pthread_mutex_unlock(&replyq->mutex);
- cnt = write(client->s, reply->buf, RADLEN(reply->buf));
+ cnt = write(client->sock, reply->buf, RADLEN(reply->buf));
if (cnt > 0)
debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d",
cnt, RADLEN(reply->buf));
@@ -3106,7 +3394,7 @@ void tcpserverrd(struct client *client) {
for (;;) {
memset(&rq, 0, sizeof(struct request));
- rq.buf = radtcpget(client->s, 0);
+ rq.buf = radtcpget(client->sock, 0);
if (!rq.buf) {
debug(DBG_ERR, "tcpserverrd: connection from %s lost", client->conf->host);
break;
@@ -3120,7 +3408,7 @@ void tcpserverrd(struct client *client) {
}
/* stop writer by setting s to -1 and give signal in case waiting for data */
- client->s = -1;
+ client->sock = -1;
pthread_mutex_lock(&client->replyq->mutex);
pthread_cond_signal(&client->replyq->cond);
pthread_mutex_unlock(&client->replyq->mutex);
@@ -3148,7 +3436,7 @@ void *tcpservernew(void *arg) {
if (conf) {
client = addclient(conf);
if (client) {
- client->s = s;
+ client->sock = s;
tcpserverrd(client);
removeclient(client);
} else
@@ -3242,39 +3530,34 @@ void createlisteners(uint8_t type, char **args) {
createlistener(type, NULL);
}
-void *ssl_info_callback(const SSL *s, int where, int ret) {
- const char *str;
+#ifdef DEBUG
+void ssl_info_callback(const SSL *ssl, int where, int ret) {
+ const char *s;
int w;
w = where & ~SSL_ST_MASK;
if (w & SSL_ST_CONNECT)
- str = "SSL_connect";
+ s = "SSL_connect";
else if (w & SSL_ST_ACCEPT)
- str = "SSL_accept";
+ s = "SSL_accept";
else
- str = "undefined";
+ s = "undefined";
- if (where & SSL_CB_LOOP) {
- debug(DBG_WARN, "%s:%s\n", str, SSL_state_string_long(s));
- }
+ if (where & SSL_CB_LOOP)
+ debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
else if (where & SSL_CB_ALERT) {
- str = (where & SSL_CB_READ) ? "read" : "write";
- debug(DBG_WARN, "SSL3 alert %s:%s:%s\n",
- str,
- SSL_alert_type_string_long(ret),
- SSL_alert_desc_string_long(ret));
+ s = (where & SSL_CB_READ) ? "read" : "write";
+ debug(DBG_DBG, "SSL3 alert %s:%s:%s\n", s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
}
else if (where & SSL_CB_EXIT) {
if (ret == 0)
- debug(DBG_WARN, "%s:failed in %s\n",
- str, SSL_state_string_long(s));
+ debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
else if (ret < 0)
- debug(DBG_WARN, "%s:error in %s\n",
- str,SSL_state_string_long(s));
+ debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
}
- return NULL;
}
+#endif
SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
SSL_CTX *ctx = NULL;
@@ -3307,10 +3590,15 @@ SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
switch (type) {
case RAD_TLS:
ctx = SSL_CTX_new(TLSv1_method());
+#ifdef DEBUG
+ SSL_CTX_set_info_callback(ctx, ssl_info_callback);
+#endif
break;
case RAD_DTLS:
ctx = SSL_CTX_new(DTLSv1_method());
+#ifdef DEBUG
SSL_CTX_set_info_callback(ctx, ssl_info_callback);
+#endif
SSL_CTX_set_read_ahead(ctx, 1);
break;
}
@@ -4437,15 +4725,6 @@ int main(int argc, char **argv) {
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
pthread_create(&sigth, NULL, sighandler, NULL);
- if (find_conf_type(RAD_UDP, clconfs, NULL) || find_conf_type(RAD_DTLS, clconfs, NULL)) {
- udp_server_replyq = newreplyq();
- if (pthread_create(&udpserverwrth, NULL, udpserverwr, NULL))
- debugx(1, DBG_ERR, "pthread_create failed");
- createlisteners(RAD_UDP, options.listenudp);
- if (options.listenaccudp)
- createlisteners(RAD_UDP, options.listenaccudp);
- }
-
for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
srvconf = (struct clsrvconf *)entry->data;
if (srvconf->dynamiclookupcommand)
@@ -4461,6 +4740,7 @@ int main(int argc, char **argv) {
freeaddrinfo(srcprotores[RAD_UDP]);
srcprotores[RAD_UDP] = NULL;
}
+
if (udp_client4_sock >= 0)
if (pthread_create(&udpclient4rdth, NULL, protodefs[RAD_UDP].clientreader, (void *)&udp_client4_sock))
debugx(1, DBG_ERR, "pthread_create failed");
@@ -4474,6 +4754,15 @@ int main(int argc, char **argv) {
if (find_conf_type(RAD_TLS, clconfs, NULL))
createlisteners(RAD_TLS, options.listentls);
+ if (find_conf_type(RAD_UDP, clconfs, NULL) || find_conf_type(RAD_DTLS, clconfs, NULL)) {
+ udp_server_replyq = newqueue();
+ if (pthread_create(&udpserverwrth, NULL, udpserverwr, NULL))
+ debugx(1, DBG_ERR, "pthread_create failed");
+ createlisteners(RAD_UDP, options.listenudp);
+ if (options.listenaccudp)
+ createlisteners(RAD_UDP, options.listenaccudp);
+ }
+
/* just hang around doing nothing, anything to do here? */
for (;;)
sleep(1000);
diff --git a/radsecproxy.h b/radsecproxy.h
index b38f6f0..95506a2 100644
--- a/radsecproxy.h
+++ b/radsecproxy.h
@@ -76,8 +76,8 @@ struct reply {
int toudpsock; /* used by udpservwr */
};
-struct replyq {
- struct list *replies;
+struct queue {
+ struct list *entries;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
@@ -112,9 +112,11 @@ struct clsrvconf {
struct client {
struct clsrvconf *conf;
- int s; /* for tcp */
+ int sock; /* for tcp/dtls */
SSL *ssl;
- struct replyq *replyq;
+ struct queue *replyq;
+ struct queue *rbios; /* for dtls */
+ struct sockaddr_storage addr; /* for dtls */
};
struct server {
@@ -135,6 +137,7 @@ struct server {
uint8_t newrq;
pthread_mutex_t newrq_mutex;
pthread_cond_t newrq_cond;
+ struct queue *rbios; /* for dtls */
};
struct realm {