diff options
-rw-r--r-- | dtls.c | 122 | ||||
-rw-r--r-- | dtls.h | 1 | ||||
-rw-r--r-- | hash.c | 22 | ||||
-rw-r--r-- | hash.h | 3 | ||||
-rw-r--r-- | radsecproxy.c | 9 | ||||
-rw-r--r-- | radsecproxy.h | 2 |
6 files changed, 109 insertions, 50 deletions
@@ -28,6 +28,7 @@ #include <openssl/err.h> #include "debug.h" #include "list.h" +#include "hash.h" #include "util.h" #include "radsecproxy.h" #include "dtls.h" @@ -96,12 +97,16 @@ void *udpdtlsserverrd(void *arg) { unsigned char buf[4]; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); - struct clsrvconf *conf; - struct list_node *node; struct client *client; fd_set readfds; pthread_t dtlsserverth; - + struct hash *rbiosh; + struct queue *rbiosq; + + rbiosh = hash_create(); + if (!rbiosh) + debugx(1, DBG_ERR, "udpdtlsserverrd: malloc failed"); + for (;;) { FD_ZERO(&readfds); FD_SET(s, &readfds); @@ -112,34 +117,36 @@ void *udpdtlsserverrd(void *arg) { debug(DBG_WARN, "udpdtlsserverrd: recv failed"); continue; } - conf = find_clconf(RAD_DTLS, (struct sockaddr *)&from, NULL); - if (!conf) { - debug(DBG_WARN, "udpdtlsserverrd: got packet from wrong or unknown DTLS peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen)); - recv(s, buf, 4, 0); + rbiosq = hash_read(rbiosh, &from, fromlen); + if (rbiosq) { + if (udp2bio(s, rbiosq, cnt)) + debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen)); continue; } - - node = list_first(conf->clients); - if (node) - client = (struct client *)node->data; - else { - client = addclient(conf); - if (!client) { - recv(s, buf, 4, 0); - continue; - } - client->sock = s; - memcpy(&client->addr, &from, fromlen); - if (pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)client)) { - debug(DBG_ERR, "udpdtlsserverrd: pthread_create failed"); - removeclient(client); - recv(s, buf, 4, 0); + + /* from new source, new client? */ + client = malloc(sizeof(struct client)); + if (!client) + continue; + client->rbios = rbiosq = newqueue(); + if (!hash_insert(rbiosh, &from, fromlen, rbiosq)) { + free(client); + removequeue(rbiosq); + continue; + } + client->sock = s; + memcpy(&client->addr, &from, fromlen); + + if (udp2bio(s, rbiosq, cnt)) { + debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen)); + if (!pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)client)) { + pthread_detach(dtlsserverth); continue; } - pthread_detach(dtlsserverth); + debug(DBG_ERR, "udpdtlsserverrd: pthread_create failed"); } - if (udp2bio(s, client->rbios, cnt)) - debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen)); + free(client); + freebios(hash_extract(rbiosh, &from, fromlen)); } } @@ -323,26 +330,56 @@ SSL *dtlsacccon(uint8_t acc, SSL_CTX *ctx, int s, struct sockaddr *addr, struct } void *dtlsservernew(void *arg) { - struct client *client = (struct client *)arg; + struct client *client, *clpar = (struct client *)arg; + struct clsrvconf *conf; + struct list_node *cur = NULL; + int s; + SSL *ssl = NULL; X509 *cert = NULL; + struct queue *rbios; + struct sockaddr_storage addr; + + s = clpar->sock; + rbios = clpar->rbios; + addr = clpar->addr; + free(clpar); + + conf = find_clconf(RAD_DTLS, (struct sockaddr *)&addr, NULL); + if (conf) { + ssl = dtlsacccon(1, conf->ssl_ctx, s, (struct sockaddr *)&addr, rbios); + if (!ssl) + goto exit; + cert = verifytlscert(ssl); + if (!cert) + goto exit; + } + + while (conf) { + if (verifyconfcert(cert, conf)) { + X509_free(cert); + client = addclient(conf); + if (client) { + client->sock = s; + client->rbios = rbios; + client->addr = addr; + client->ssl = ssl; + dtlsserverrd(client); + removeclient(client); + } else { + debug(DBG_WARN, "dtlsservernew: failed to create new client instance"); + } + goto exit; + } + conf = find_clconf(RAD_DTLS, (struct sockaddr *)&client->addr, &cur); + } + debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client"); - 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); + /* mark rbios for removal, to be removed by udpdtlsserverrd()*/ + SSL_free(ssl); ERR_remove_state(0); pthread_exit(NULL); } @@ -474,11 +511,6 @@ void *dtlsclientrd(void *arg) { } } -void addclientdtls(struct client *client) { - client->replyq = newqueue(); - client->rbios = newqueue(); -} - void addserverextradtls(struct clsrvconf *conf) { switch (conf->addrinfo->ai_family) { case AF_INET: @@ -12,6 +12,5 @@ void *dtlsservernew(void *arg); void *dtlsclientrd(void *arg); void *udpdtlsclientrd(void *arg); int clientradputdtls(struct server *server, unsigned char *rad); -void addclientdtls(struct client *client); void addserverextradtls(struct clsrvconf *conf); void initextradtls(); @@ -92,3 +92,25 @@ void *hash_read(struct hash *h, void *key, uint32_t keylen) { pthread_mutex_unlock(&h->mutex); return NULL; } + +/* extracts entry from hash */ +void *hash_extract(struct hash *h, void *key, uint32_t keylen) { + struct list_node *ln; + struct entry *e; + + if (!h) + return 0; + pthread_mutex_lock(&h->mutex); + for (ln = list_first(h->hashlist); ln; ln = list_next(ln)) { + e = (struct entry *)ln->data; + if (e->keylen == keylen && !memcmp(e->key, key, keylen)) { + free(e->key); + list_removedata(h->hashlist, e); + free(e); + pthread_mutex_unlock(&h->mutex); + return e->data; + } + } + pthread_mutex_unlock(&h->mutex); + return NULL; +} @@ -24,3 +24,6 @@ int hash_insert(struct hash *hash, void *key, uint32_t keylen, void *data); /* reads entry from hash */ void *hash_read(struct hash *hash, void *key, uint32_t keylen); + +/* extracts (read and remove) entry from hash */ +void *hash_extract(struct hash *hash, void *key, uint32_t keylen); diff --git a/radsecproxy.c b/radsecproxy.c index c97e7ed..50bdd20 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -155,7 +155,7 @@ static const struct protodefs protodefs[] = { dtlsconnect, /* connecter */ dtlsclientrd, /* clientconnreader */ clientradputdtls, /* clientradput */ - addclientdtls, /* addclient */ + NULL, /* addclient */ addserverextradtls, /* addserverextra */ initextradtls /* initextra */ }, @@ -528,7 +528,9 @@ struct queue *newqueue() { void removequeue(struct queue *q) { struct list_node *entry; - + + if (!q) + return; pthread_mutex_lock(&q->mutex); for (entry = list_first(q->entries); entry; entry = list_next(entry)) free(((struct reply *)entry)->buf); @@ -536,6 +538,7 @@ void removequeue(struct queue *q) { pthread_cond_destroy(&q->cond); pthread_mutex_unlock(&q->mutex); pthread_mutex_destroy(&q->mutex); + free(q); } void freebios(struct queue *q) { @@ -577,8 +580,6 @@ void removeclient(struct client *client) { if (!client || !client->conf->clients) return; removequeue(client->replyq); - if (client->rbios) - freebios(client->rbios); list_removedata(client->conf->clients, client); free(client); } diff --git a/radsecproxy.h b/radsecproxy.h index 2546470..e9f3bed 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -208,6 +208,8 @@ struct client *addclient(struct clsrvconf *conf); void removeclient(struct client *client); void removeclientrqs(struct client *client); struct queue *newqueue(); +void removequeue(struct queue *q); +void freebios(struct queue *q); int radsrv(struct request *rq); X509 *verifytlscert(SSL *ssl); int verifyconfcert(X509 *cert, struct clsrvconf *conf); |