From d66ccd060ebc434559c6520b6408148193e13a07 Mon Sep 17 00:00:00 2001 From: venaas Date: Wed, 20 Aug 2008 09:34:56 +0000 Subject: finally basic dtls functionality in place git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@345 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- radsecproxy.c | 607 +++++++++++++++++++++++++++++++++++++++++++--------------- radsecproxy.h | 11 +- 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 { -- cgit v1.2.3