diff options
| -rw-r--r-- | radsecproxy.c | 607 | ||||
| -rw-r--r-- | 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 { | 
