#include "util.h"
#include "gconfig.h"
#include "radsecproxy.h"
+#include "udp.h"
+#include "tcp.h"
+#include "tls.h"
+#include "dtls.h"
static struct options options;
-struct list *clconfs, *srvconfs, *realms, *tlsconfs, *rewriteconfs;
+static struct list *clconfs, *srvconfs;
+struct list *realms, *tlsconfs, *rewriteconfs;
-static struct addrinfo *srcprotores[3] = { NULL, NULL, NULL };
+static struct addrinfo *srcprotores[4] = { NULL, 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 int dtls_client4_sock = -1;
+static int dtls_client6_sock = -1;
static pthread_mutex_t tlsconfs_lock;
static pthread_mutex_t *ssl_locks = NULL;
static long *ssl_lock_count;
void freerealm(struct realm *realm);
void freeclsrvconf(struct clsrvconf *conf);
void freerqdata(struct request *rq);
-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 tcpconnect(struct server *server, struct timeval *when, int timeout, char *text);
-void *udpclientrd(void *arg);
-void *tlsclientrd(void *arg);
-void *tcpclientrd(void *arg);
-int clientradputudp(struct server *server, unsigned char *rad);
-int clientradputtls(struct server *server, unsigned char *rad);
-int clientradputtcp(struct server *server, unsigned char *rad);
-
+
static const struct protodefs protodefs[] = {
{ "udp", /* UDP, assuming RAD_UDP defined as 0 */
NULL, /* secretdefault */
clientradputtcp /* clientradput */
},
{ "dtls", /* DTLS, assuming RAD_DTLS defined as 3 */
- NULL, /* secretdefault */
+ "mysecret", /* secretdefault */
SOCK_DGRAM, /* socktype */
- "1812", /* portdefault */
+ "2083", /* portdefault */
REQUEST_RETRY_COUNT, /* retrycountdefault */
10, /* retrycountmax */
REQUEST_RETRY_INTERVAL, /* retryintervaldefault */
60, /* retryintervalmax */
- udpserverrd, /* listener */
- &options.sourceudp, /* srcaddrport */
- tlsconnect, /* connecter */
- udpclientrd, /* clientreader */
- clientradputudp /* clientradput */
+ udpdtlsserverrd, /* listener */
+ &options.sourcedtls, /* srcaddrport */
+ dtlsconnect, /* connecter */
+ dtlsclientrd, /* clientreader */
+ clientradputdtls /* clientradput */
},
{ NULL
}
return ok;
}
+struct addrinfo *getsrcprotores(uint8_t type) {
+ return srcprotores[type];
+}
+
int resolvepeer(struct clsrvconf *conf, int ai_flags) {
struct addrinfo hints, *addrinfo, *res;
char *slash, *s;
return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
}
-/* check if conf has matching address */
-struct clsrvconf *checkconfaddr(uint8_t type, struct sockaddr *addr, struct clsrvconf *conf) {
- struct sockaddr_in6 *sa6 = NULL;
- struct in_addr *a4 = NULL;
- struct addrinfo *res;
-
- if (addr->sa_family == AF_INET6) {
- sa6 = (struct sockaddr_in6 *)addr;
- if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
- a4 = (struct in_addr *)&sa6->sin6_addr.s6_addr[12];
- sa6 = NULL;
- }
- } else
- a4 = &((struct sockaddr_in *)addr)->sin_addr;
-
- if (conf->type == type) {
- if (conf->prefixlen == 255) {
- for (res = conf->addrinfo; res; res = res->ai_next)
- if ((a4 && res->ai_family == AF_INET &&
- !memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) ||
- (sa6 && res->ai_family == AF_INET6 &&
- !memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16)))
- return conf;
- } else {
- res = conf->addrinfo;
- if (res &&
- ((a4 && res->ai_family == AF_INET &&
- prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, conf->prefixlen)) ||
- (sa6 && res->ai_family == AF_INET6 &&
- prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, conf->prefixlen))))
- return conf;
- }
- }
- return NULL;
-}
-
/* returns next config with matching address, or NULL */
struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur) {
struct sockaddr_in6 *sa6 = NULL;
return NULL;
}
+struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
+ return find_conf(type, addr, clconfs, cur);
+}
+
+struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
+ return find_conf(type, addr, srvconfs, cur);
+}
+
/* returns next config of given type, or NULL */
struct clsrvconf *find_conf_type(uint8_t type, struct list *confs, struct list_node **cur) {
struct list_node *entry;
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) {
memset(new, 0, sizeof(struct client));
new->conf = conf;
- new->replyq = conf->type == RAD_UDP ? 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);
}
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);
type = conf->type;
if (type == RAD_DTLS)
- type = RAD_UDP;
+ conf->servers->rbios = newqueue();
if (!srcprotores[type]) {
res = resolve_hostport(type, *conf->pdef->srcaddrport, NULL);
freeclsrvres(res);
}
- if (type == RAD_UDP) {
+ switch (type) {
+ case RAD_UDP:
switch (conf->addrinfo->ai_family) {
case AF_INET:
if (udp_client4_sock < 0) {
default:
debugx(1, DBG_ERR, "addserver: unsupported address family");
}
-
- } else
+ break;
+ case RAD_DTLS:
+ switch (conf->addrinfo->ai_family) {
+ case AF_INET:
+ if (dtls_client4_sock < 0) {
+ dtls_client4_sock = bindtoaddr(srcprotores[RAD_DTLS], AF_INET, 0, 1);
+ if (dtls_client4_sock < 0)
+ debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
+ }
+ conf->servers->sock = dtls_client4_sock;
+ break;
+ case AF_INET6:
+ if (dtls_client6_sock < 0) {
+ dtls_client6_sock = bindtoaddr(srcprotores[RAD_DTLS], AF_INET6, 0, 1);
+ if (dtls_client6_sock < 0)
+ debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
+ }
+ conf->servers->sock = dtls_client6_sock;
+ break;
+ default:
+ debugx(1, DBG_ERR, "addserver: unsupported address family");
+ }
+ break;
+ default:
conf->servers->sock = -1;
+ }
conf->servers->requests = calloc(MAX_REQUESTS, sizeof(struct request));
if (!conf->servers->requests) {
return 0;
}
-/* exactly one of client and server must be non-NULL */
-/* should probably take peer list (client(s) or server(s)) as argument instead */
-/* if *peer == NULL we return who we received from, else require it to be from peer */
-/* return from in sa if not NULL */
-unsigned char *radudpget(int s, struct client **client, struct server **server, struct sockaddr_storage *sa) {
- int cnt, len;
- unsigned char buf[4], *rad;
- struct sockaddr_storage from;
- socklen_t fromlen = sizeof(from);
- struct clsrvconf *p;
- struct list_node *node;
- fd_set readfds;
-
- for (;;) {
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
- if (select(s + 1, &readfds, NULL, NULL, NULL) < 1)
- continue;
- cnt = recvfrom(s, buf, 4, MSG_PEEK, (struct sockaddr *)&from, &fromlen);
- if (cnt == -1) {
- debug(DBG_WARN, "radudpget: recv failed");
- continue;
- }
-
- if (client)
- if (*client)
- p = checkconfaddr(RAD_UDP, (struct sockaddr *)&from, (*client)->conf);
- else
- p = find_conf(RAD_UDP, (struct sockaddr *)&from, clconfs, NULL);
- else
- if (*server)
- p = checkconfaddr(RAD_UDP, (struct sockaddr *)&from, (*server)->conf);
- else
- p = find_conf(RAD_UDP, (struct sockaddr *)&from, srvconfs, NULL);
-
- if (!p) {
- debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen));
- recv(s, buf, 4, 0);
- continue;
- }
-
- len = RADLEN(buf);
- if (len < 20) {
- debug(DBG_WARN, "radudpget: length too small");
- recv(s, buf, 4, 0);
- continue;
- }
-
- rad = malloc(len);
- if (!rad) {
- debug(DBG_ERR, "radudpget: malloc failed");
- recv(s, buf, 4, 0);
- continue;
- }
-
- cnt = recv(s, rad, len, MSG_TRUNC);
- debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from, fromlen));
-
- if (cnt < len) {
- debug(DBG_WARN, "radudpget: packet smaller than length field in radius header");
- free(rad);
- continue;
- }
-
- if (cnt > len)
- debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);
-
- if (client && !*client) {
- node = list_first(p->clients);
- *client = node ? (struct client *)node->data : addclient(p);
- if (!*client) {
- free(rad);
- continue;
- }
- } else if (server && !*server)
- *server = p->servers;
-
- break;
- }
- if (sa)
- *sa = from;
- return rad;
-}
-
int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) {
int loc, i, l, n, r = 0;
char *v;
return 1;
}
-int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
- struct timeval now;
- time_t elapsed;
- X509 *cert;
-
- debug(DBG_DBG, "tlsconnect: 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, "tlsconnect(%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, "tlsconnect: timeout");
- if (server->sock >= 0)
- close(server->sock);
- 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, "tlsconnect: sleeping %lds", elapsed);
- sleep(elapsed);
- } else if (elapsed < 100000) {
- debug(DBG_INFO, "tlsconnect: sleeping %ds", 60);
- sleep(60);
- } else
- server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */
- debug(DBG_WARN, "tlsconnect: trying to open TLS connection to %s port %s", server->conf->host, server->conf->port);
- if (server->sock >= 0)
- close(server->sock);
- if ((server->sock = connecttcp(server->conf->addrinfo, srcprotores[RAD_TLS])) < 0) {
- debug(DBG_ERR, "tlsconnect: connecttcp failed");
- continue;
- }
-
- SSL_free(server->ssl);
- server->ssl = SSL_new(server->conf->ssl_ctx);
- SSL_set_fd(server->ssl, server->sock);
- if (SSL_connect(server->ssl) <= 0)
- continue;
- cert = verifytlscert(server->ssl);
- if (!cert)
- continue;
- if (verifyconfcert(cert, server->conf)) {
- X509_free(cert);
- break;
- }
- X509_free(cert);
- }
- debug(DBG_WARN, "tlsconnect: TLS 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;
-
- debug(DBG_DBG, "tcpconnect: 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, "tcpconnect(%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, "tcpconnect: timeout");
- if (server->sock >= 0)
- close(server->sock);
- 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, "tcpconnect: sleeping %lds", elapsed);
- sleep(elapsed);
- } else if (elapsed < 100000) {
- debug(DBG_INFO, "tcpconnect: sleeping %ds", 60);
- sleep(60);
- } else
- server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */
- debug(DBG_WARN, "tcpconnect: trying to open TCP connection to %s port %s", server->conf->host, server->conf->port);
- if (server->sock >= 0)
- close(server->sock);
- if ((server->sock = connecttcp(server->conf->addrinfo, srcprotores[RAD_TCP])) >= 0)
- break;
- debug(DBG_ERR, "tcpconnect: connecttcp failed");
- }
- debug(DBG_WARN, "tcpconnect: TCP connection to %s port %s up", server->conf->host, server->conf->port);
- gettimeofday(&server->lastconnecttry, NULL);
- pthread_mutex_unlock(&server->lock);
- return 1;
-}
-
-/* timeout in seconds, 0 means no timeout (blocking), returns when num bytes have been read, or timeout */
-/* returns 0 on timeout, -1 on error and num if ok */
-int sslreadtimeout(SSL *ssl, unsigned char *buf, int num, int timeout) {
- int s, ndesc, cnt, len;
- fd_set readfds, writefds;
- struct timeval timer;
-
- s = SSL_get_fd(ssl);
- if (s < 0)
- return -1;
- /* make socket non-blocking? */
- for (len = 0; len < num; len += cnt) {
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
- writefds = readfds;
- if (timeout) {
- timer.tv_sec = timeout;
- timer.tv_usec = 0;
- }
- ndesc = select(s + 1, &readfds, &writefds, NULL, timeout ? &timer : NULL);
- if (ndesc < 1)
- return ndesc;
-
- cnt = SSL_read(ssl, buf + len, num - len);
- if (cnt <= 0)
- switch (SSL_get_error(ssl, cnt)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- cnt = 0;
- continue;
- case SSL_ERROR_ZERO_RETURN:
- /* remote end sent close_notify, send one back */
- SSL_shutdown(ssl);
- /* fall through */
- default:
- return -1;
- }
- }
- return num;
-}
-
-/* timeout in seconds, 0 means no timeout (blocking) */
-unsigned char *radtlsget(SSL *ssl, int timeout) {
- int cnt, len;
- unsigned char buf[4], *rad;
-
- for (;;) {
- cnt = sslreadtimeout(ssl, buf, 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout");
- return NULL;
- }
-
- len = RADLEN(buf);
- rad = malloc(len);
- if (!rad) {
- debug(DBG_ERR, "radtlsget: malloc failed");
- continue;
- }
- memcpy(rad, buf, 4);
-
- cnt = sslreadtimeout(ssl, rad + 4, len - 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout");
- free(rad);
- return NULL;
- }
-
- if (len >= 20)
- break;
-
- free(rad);
- debug(DBG_WARN, "radtlsget: packet smaller than minimum radius size");
- }
-
- debug(DBG_DBG, "radtlsget: got %d bytes", len);
- return rad;
-}
-
-/* timeout in seconds, 0 means no timeout (blocking), returns when num bytes have been read, or timeout */
-/* returns 0 on timeout, -1 on error and num if ok */
-int tcpreadtimeout(int s, unsigned char *buf, int num, int timeout) {
- int ndesc, cnt, len;
- fd_set readfds, writefds;
- struct timeval timer;
-
- if (s < 0)
- return -1;
- /* make socket non-blocking? */
- for (len = 0; len < num; len += cnt) {
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
- writefds = readfds;
- if (timeout) {
- timer.tv_sec = timeout;
- timer.tv_usec = 0;
- }
- ndesc = select(s + 1, &readfds, &writefds, NULL, timeout ? &timer : NULL);
- if (ndesc < 1)
- return ndesc;
-
- cnt = read(s, buf + len, num - len);
- if (cnt <= 0)
- return -1;
- }
- return num;
-}
-
-/* timeout in seconds, 0 means no timeout (blocking) */
-unsigned char *radtcpget(int s, int timeout) {
- int cnt, len;
- unsigned char buf[4], *rad;
-
- for (;;) {
- cnt = tcpreadtimeout(s, buf, 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtcpget: connection lost" : "radtcpget: timeout");
- return NULL;
- }
-
- len = RADLEN(buf);
- rad = malloc(len);
- if (!rad) {
- debug(DBG_ERR, "radtcpget: malloc failed");
- continue;
- }
- memcpy(rad, buf, 4);
-
- cnt = tcpreadtimeout(s, rad + 4, len - 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtcpget: connection lost" : "radtcpget: timeout");
- free(rad);
- return NULL;
- }
-
- if (len >= 20)
- break;
-
- free(rad);
- debug(DBG_WARN, "radtcpget: packet smaller than minimum radius size");
- }
-
- debug(DBG_DBG, "radtcpget: got %d bytes", len);
- return rad;
-}
-
-int clientradputudp(struct server *server, unsigned char *rad) {
- size_t len;
- struct sockaddr_storage sa;
- struct sockaddr *sap;
- struct clsrvconf *conf = server->conf;
- in_port_t *port = NULL;
-
- len = RADLEN(rad);
-
- if (*rad == RAD_Accounting_Request) {
- sap = (struct sockaddr *)&sa;
- memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen);
- } else
- sap = conf->addrinfo->ai_addr;
-
- switch (sap->sa_family) {
- case AF_INET:
- port = &((struct sockaddr_in *)sap)->sin_port;
- break;
- case AF_INET6:
- port = &((struct sockaddr_in6 *)sap)->sin6_port;
- break;
- default:
- return 0;
- }
-
- if (*rad == RAD_Accounting_Request)
- *port = htons(ntohs(*port) + 1);
-
- if (sendto(server->sock, rad, len, 0, sap, conf->addrinfo->ai_addrlen) >= 0) {
- debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, ntohs(*port));
- return 1;
- }
-
- debug(DBG_WARN, "clientradputudp: send failed");
- return 0;
-}
-
-int clientradputtls(struct server *server, unsigned char *rad) {
- int cnt;
- size_t len;
- unsigned long error;
- struct timeval lastconnecttry;
- struct clsrvconf *conf = server->conf;
-
- len = RADLEN(rad);
- lastconnecttry = server->lastconnecttry;
- while ((cnt = SSL_write(server->ssl, rad, len)) <= 0) {
- while ((error = ERR_get_error()))
- debug(DBG_ERR, "clientradputtls: TLS: %s", ERR_error_string(error, NULL));
- if (server->dynamiclookuparg)
- return 0;
- tlsconnect(server, &lastconnecttry, 0, "clientradputtls");
- lastconnecttry = server->lastconnecttry;
- }
-
- server->connectionok = 1;
- debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->host);
- return 1;
-}
-
-int clientradputtcp(struct server *server, unsigned char *rad) {
- int cnt;
- size_t len;
- struct timeval lastconnecttry;
- struct clsrvconf *conf = server->conf;
-
- len = RADLEN(rad);
- lastconnecttry = server->lastconnecttry;
- while ((cnt = write(server->sock, rad, len)) <= 0) {
- debug(DBG_ERR, "clientradputtcp: write error");
- tcpconnect(server, &lastconnecttry, 0, "clientradputtcp");
- lastconnecttry = server->lastconnecttry;
- }
-
- server->connectionok = 1;
- debug(DBG_DBG, "clientradputtcp: Sent %d bytes, Radius packet of length %d to TCP peer %s", cnt, len, conf->host);
- return 1;
-}
-
int radsign(unsigned char *rad, unsigned char *sec) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1;
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);
return 1;
}
-void *udpclientrd(void *arg) {
- struct server *server;
- unsigned char *buf;
- int *s = (int *)arg;
-
- for (;;) {
- server = NULL;
- buf = radudpget(*s, NULL, &server, NULL);
- if (!replyh(server, buf))
- free(buf);
- }
-}
-
-void *tlsclientrd(void *arg) {
- struct server *server = (struct server *)arg;
- unsigned char *buf;
- struct timeval now, lastconnecttry;
-
- for (;;) {
- /* yes, lastconnecttry is really necessary */
- lastconnecttry = server->lastconnecttry;
- buf = radtlsget(server->ssl, server->dynamiclookuparg ? IDLE_TIMEOUT : 0);
- if (!buf) {
- if (server->dynamiclookuparg)
- break;
- tlsconnect(server, &lastconnecttry, 0, "tlsclientrd");
- continue;
- }
-
- if (!replyh(server, buf))
- free(buf);
- if (server->dynamiclookuparg) {
- gettimeofday(&now, NULL);
- if (now.tv_sec - server->lastreply.tv_sec > IDLE_TIMEOUT) {
- debug(DBG_INFO, "tlsclientrd: idle timeout for %s", server->conf->name);
- break;
- }
- }
- }
- ERR_remove_state(0);
- server->clientrdgone = 1;
- return NULL;
-}
-
-void *tcpclientrd(void *arg) {
- struct server *server = (struct server *)arg;
- unsigned char *buf;
- struct timeval lastconnecttry;
-
- for (;;) {
- /* yes, lastconnecttry is really necessary */
- lastconnecttry = server->lastconnecttry;
- buf = radtcpget(server->sock, 0);
- if (!buf) {
- tcpconnect(server, &lastconnecttry, 0, "tcpclientrd");
- continue;
- }
-
- if (!replyh(server, buf))
- free(buf);
- }
- server->clientrdgone = 1;
- return NULL;
-}
-
/* code for removing state not finished */
void *clientwr(void *arg) {
struct server *server = (struct server *)arg;
return NULL;
}
-void *udpserverwr(void *arg) {
- struct replyq *replyq = udp_server_replyq;
- struct reply *reply;
-
- for (;;) {
- pthread_mutex_lock(&replyq->mutex);
- while (!(reply = (struct reply *)list_shift(replyq->replies))) {
- debug(DBG_DBG, "udp server writer, waiting for signal");
- pthread_cond_wait(&replyq->cond, &replyq->mutex);
- debug(DBG_DBG, "udp server writer, got signal");
- }
- pthread_mutex_unlock(&replyq->mutex);
-
- if (sendto(reply->toudpsock, reply->buf, RADLEN(reply->buf), 0,
- (struct sockaddr *)&reply->tosa, SOCKADDR_SIZE(reply->tosa)) < 0)
- debug(DBG_WARN, "sendudp: send failed");
- free(reply->buf);
- free(reply);
- }
-}
-
-void *udpserverrd(void *arg) {
- struct request rq;
- int *sp = (int *)arg;
-
- for (;;) {
- memset(&rq, 0, sizeof(struct request));
- rq.buf = radudpget(*sp, &rq.from, NULL, &rq.fromsa);
- rq.fromudpsock = *sp;
- radsrv(&rq);
- }
- free(sp);
-}
-
-void *tlsserverwr(void *arg) {
- int cnt;
- unsigned long error;
- struct client *client = (struct client *)arg;
- struct replyq *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)) {
- if (client->ssl) {
- debug(DBG_DBG, "tlsserverwr: waiting for signal");
- pthread_cond_wait(&replyq->cond, &replyq->mutex);
- debug(DBG_DBG, "tlsserverwr: got signal");
- }
- if (!client->ssl) {
- /* ssl might have changed while waiting */
- pthread_mutex_unlock(&replyq->mutex);
- debug(DBG_DBG, "tlsserverwr: exiting as requested");
- ERR_remove_state(0);
- pthread_exit(NULL);
- }
- }
- reply = (struct reply *)list_shift(replyq->replies);
- pthread_mutex_unlock(&replyq->mutex);
- cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf));
- if (cnt > 0)
- debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d",
- cnt, RADLEN(reply->buf));
- else
- while ((error = ERR_get_error()))
- debug(DBG_ERR, "tlsserverwr: SSL: %s", ERR_error_string(error, NULL));
- free(reply->buf);
- free(reply);
- }
-}
-
-void tlsserverrd(struct client *client) {
- struct request rq;
- pthread_t tlsserverwrth;
-
- debug(DBG_DBG, "tlsserverrd: starting for %s", client->conf->host);
-
- if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) {
- debug(DBG_ERR, "tlsserverrd: pthread_create failed");
- return;
- }
-
- for (;;) {
- memset(&rq, 0, sizeof(struct request));
- rq.buf = radtlsget(client->ssl, 0);
- if (!rq.buf) {
- debug(DBG_ERR, "tlsserverrd: connection from %s lost", client->conf->host);
- break;
- }
- debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host);
- rq.from = client;
- if (!radsrv(&rq)) {
- debug(DBG_ERR, "tlsserverrd: 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, "tlsserverrd: waiting for writer to end");
- pthread_join(tlsserverwrth, NULL);
- removeclientrqs(client);
- debug(DBG_DBG, "tlsserverrd: reader for %s exiting", client->conf->host);
-}
-
-void *tlsservernew(void *arg) {
- int s;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
- struct clsrvconf *conf;
- struct list_node *cur = NULL;
- SSL *ssl = NULL;
- X509 *cert = NULL;
- unsigned long error;
- struct client *client;
-
- s = *(int *)arg;
- if (getpeername(s, (struct sockaddr *)&from, &fromlen)) {
- debug(DBG_DBG, "tlsservernew: getpeername failed, exiting");
- goto exit;
- }
- debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, fromlen));
-
- conf = find_conf(RAD_TLS, (struct sockaddr *)&from, clconfs, &cur);
- if (conf) {
- ssl = SSL_new(conf->ssl_ctx);
- SSL_set_fd(ssl, s);
-
- if (SSL_accept(ssl) <= 0) {
- while ((error = ERR_get_error()))
- debug(DBG_ERR, "tlsservernew: SSL: %s", ERR_error_string(error, NULL));
- debug(DBG_ERR, "tlsservernew: SSL_accept failed");
- goto exit;
- }
- cert = verifytlscert(ssl);
- if (!cert)
- goto exit;
- }
-
- while (conf) {
- if (verifyconfcert(cert, conf)) {
- X509_free(cert);
- client = addclient(conf);
- if (client) {
- client->ssl = ssl;
- tlsserverrd(client);
- removeclient(client);
- } else
- debug(DBG_WARN, "tlsservernew: failed to create new client instance");
- goto exit;
- }
- conf = find_conf(RAD_TLS, (struct sockaddr *)&from, clconfs, &cur);
- }
- debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client");
- if (cert)
- X509_free(cert);
-
- exit:
- SSL_free(ssl);
- ERR_remove_state(0);
- shutdown(s, SHUT_RDWR);
- close(s);
- pthread_exit(NULL);
-}
-
-void *tlslistener(void *arg) {
- pthread_t tlsserverth;
- int s, *sp = (int *)arg;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
-
- listen(*sp, 0);
-
- for (;;) {
- s = accept(*sp, (struct sockaddr *)&from, &fromlen);
- if (s < 0) {
- debug(DBG_WARN, "accept failed");
- continue;
- }
- if (pthread_create(&tlsserverth, NULL, tlsservernew, (void *)&s)) {
- debug(DBG_ERR, "tlslistener: pthread_create failed");
- shutdown(s, SHUT_RDWR);
- close(s);
- continue;
- }
- pthread_detach(tlsserverth);
- }
- free(sp);
- return NULL;
-}
-
-void *tcpserverwr(void *arg) {
- int cnt;
- struct client *client = (struct client *)arg;
- struct replyq *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) {
- debug(DBG_DBG, "tcpserverwr: waiting for signal");
- pthread_cond_wait(&replyq->cond, &replyq->mutex);
- debug(DBG_DBG, "tcpserverwr: got signal");
- }
- if (client->s < 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);
- pthread_mutex_unlock(&replyq->mutex);
- cnt = write(client->s, reply->buf, RADLEN(reply->buf));
- if (cnt > 0)
- debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d",
- cnt, RADLEN(reply->buf));
- else
- debug(DBG_ERR, "tcpserverwr: write error for %s", client->conf->host);
- free(reply->buf);
- free(reply);
- }
-}
-
-void tcpserverrd(struct client *client) {
- struct request rq;
- pthread_t tcpserverwrth;
-
- debug(DBG_DBG, "tcpserverrd: starting for %s", client->conf->host);
-
- if (pthread_create(&tcpserverwrth, NULL, tcpserverwr, (void *)client)) {
- debug(DBG_ERR, "tcpserverrd: pthread_create failed");
- return;
- }
-
- for (;;) {
- memset(&rq, 0, sizeof(struct request));
- rq.buf = radtcpget(client->s, 0);
- if (!rq.buf) {
- debug(DBG_ERR, "tcpserverrd: connection from %s lost", client->conf->host);
- break;
- }
- debug(DBG_DBG, "tcpserverrd: got Radius message from %s", client->conf->host);
- rq.from = client;
- if (!radsrv(&rq)) {
- debug(DBG_ERR, "tcpserverrd: message authentication/validation failed, closing connection from %s", client->conf->host);
- break;
- }
- }
-
- /* stop writer by setting s to -1 and give signal in case waiting for data */
- client->s = -1;
- pthread_mutex_lock(&client->replyq->mutex);
- pthread_cond_signal(&client->replyq->cond);
- pthread_mutex_unlock(&client->replyq->mutex);
- debug(DBG_DBG, "tcpserverrd: waiting for writer to end");
- pthread_join(tcpserverwrth, NULL);
- removeclientrqs(client);
- debug(DBG_DBG, "tcpserverrd: reader for %s exiting", client->conf->host);
-}
-
-void *tcpservernew(void *arg) {
- int s;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
- struct clsrvconf *conf;
- struct client *client;
-
- s = *(int *)arg;
- if (getpeername(s, (struct sockaddr *)&from, &fromlen)) {
- debug(DBG_DBG, "tcpservernew: getpeername failed, exiting");
- goto exit;
- }
- debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from, fromlen));
-
- conf = find_conf(RAD_TCP, (struct sockaddr *)&from, clconfs, NULL);
- if (conf) {
- client = addclient(conf);
- if (client) {
- client->s = s;
- tcpserverrd(client);
- removeclient(client);
- } else
- debug(DBG_WARN, "tcpservernew: failed to create new client instance");
- } else
- debug(DBG_WARN, "tcpservernew: ignoring request, no matching TCP client");
-
- exit:
- shutdown(s, SHUT_RDWR);
- close(s);
- pthread_exit(NULL);
-}
-
-void *tcplistener(void *arg) {
- pthread_t tcpserverth;
- int s, *sp = (int *)arg;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
-
- listen(*sp, 0);
-
- for (;;) {
- s = accept(*sp, (struct sockaddr *)&from, &fromlen);
- if (s < 0) {
- debug(DBG_WARN, "accept failed");
- continue;
- }
- if (pthread_create(&tcpserverth, NULL, tcpservernew, (void *)&s)) {
- debug(DBG_ERR, "tcplistener: pthread_create failed");
- shutdown(s, SHUT_RDWR);
- close(s);
- continue;
- }
- pthread_detach(tcpserverth);
- }
- free(sp);
- return NULL;
-}
-
void createlistener(uint8_t type, char *arg) {
pthread_t th;
struct clsrvconf *listenres;
createlistener(type, NULL);
}
+#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)
+ s = "SSL_connect";
+ else if (w & SSL_ST_ACCEPT)
+ s = "SSL_accept";
+ else
+ s = "undefined";
+
+ if (where & SSL_CB_LOOP)
+ debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
+ else if (where & SSL_CB_ALERT) {
+ 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_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
+ else if (ret < 0)
+ debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
+ }
+}
+#endif
+
SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
SSL_CTX *ctx = NULL;
STACK_OF(X509_NAME) *calist;
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;
}
"ListenUDP", CONF_MSTR, &options.listenudp,
"ListenTCP", CONF_MSTR, &options.listentcp,
"ListenTLS", CONF_MSTR, &options.listentls,
+ "ListenDTLS", CONF_MSTR, &options.listendtls,
"ListenAccountingUDP", CONF_MSTR, &options.listenaccudp,
"SourceUDP", CONF_STR, &options.sourceudp,
"SourceTCP", CONF_STR, &options.sourcetcp,
"SourceTLS", CONF_STR, &options.sourcetls,
+ "SourceDTLS", CONF_STR, &options.sourcedtls,
"LogLevel", CONF_LINT, &loglevel,
"LogDestination", CONF_STR, &options.logdestination,
"LoopPrevention", CONF_BLN, &options.loopprevention,
}
int main(int argc, char **argv) {
- pthread_t sigth, udpclient4rdth, udpclient6rdth, udpserverwrth;
+ pthread_t sigth, udpclient4rdth, udpclient6rdth, udpserverwrth, dtlsclient4rdth, dtlsclient6rdth;
sigset_t sigset;
struct list_node *entry;
uint8_t foreground = 0, pretend = 0, loglevel = 0;
if (!list_first(clconfs))
debugx(1, DBG_ERR, "No clients configured, nothing to do, exiting");
- if (!list_first(srvconfs))
- debugx(1, DBG_ERR, "No servers configured, nothing to do, exiting");
if (!list_first(realms))
debugx(1, DBG_ERR, "No realms configured, nothing to do, exiting");
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
pthread_create(&sigth, NULL, sighandler, NULL);
- if (find_conf_type(RAD_UDP, 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)
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");
if (pthread_create(&udpclient6rdth, NULL, protodefs[RAD_UDP].clientreader, (void *)&udp_client6_sock))
debugx(1, DBG_ERR, "pthread_create failed");
+ if (dtls_client4_sock >= 0)
+ if (pthread_create(&dtlsclient4rdth, NULL, udpdtlsclientrd, (void *)&dtls_client4_sock))
+ debugx(1, DBG_ERR, "pthread_create failed");
+ if (dtls_client6_sock >= 0)
+ if (pthread_create(&dtlsclient6rdth, NULL, udpdtlsclientrd, (void *)&dtls_client6_sock))
+ debugx(1, DBG_ERR, "pthread_create failed");
+
if (find_conf_type(RAD_TCP, clconfs, NULL))
createlisteners(RAD_TCP, options.listentcp);
if (find_conf_type(RAD_TLS, clconfs, NULL))
createlisteners(RAD_TLS, options.listentls);
+ if (find_conf_type(RAD_DTLS, clconfs, NULL))
+ createlisteners(RAD_DTLS, options.listendtls);
+
+ if (find_conf_type(RAD_UDP, clconfs, NULL)) {
+ udp_server_replyq = newqueue();
+ if (pthread_create(&udpserverwrth, NULL, udpserverwr, (void *)udp_server_replyq))
+ 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);