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); | 
