separated udp
[radsecproxy.git] / radsecproxy.c
index e934d55..63dba64 100644 (file)
 #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;
@@ -86,18 +93,7 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
 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 */
@@ -142,18 +138,18 @@ static const struct protodefs protodefs[] = {
        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
     }
@@ -229,6 +225,10 @@ static int verify_cb(int ok, X509_STORE_CTX *ctx) {
   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;
@@ -434,42 +434,6 @@ int prefixmatch(void *a1, void *a2, uint8_t len) {
     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;
@@ -517,6 +481,14 @@ struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *co
     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;
@@ -533,18 +505,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) {
@@ -564,25 +558,19 @@ 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);
 }
@@ -613,12 +601,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);
@@ -646,7 +636,7 @@ int addserver(struct clsrvconf *conf) {
 
     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);
@@ -655,7 +645,8 @@ int addserver(struct clsrvconf *conf) {
        freeclsrvres(res);
     }
 
-    if (type == RAD_UDP) {
+    switch (type) {
+    case RAD_UDP:
        switch (conf->addrinfo->ai_family) {
        case AF_INET:
            if (udp_client4_sock < 0) {
@@ -676,9 +667,32 @@ int addserver(struct clsrvconf *conf) {
        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) {
@@ -710,90 +724,6 @@ int addserver(struct clsrvconf *conf) {
     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;
@@ -982,348 +912,6 @@ int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
     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;
@@ -1530,9 +1118,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);
@@ -2537,71 +2125,6 @@ int replyh(struct server *server, unsigned char *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;
@@ -2774,333 +2297,6 @@ void *clientwr(void *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;
@@ -3155,6 +2351,35 @@ void createlisteners(uint8_t type, char **args) {
        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;
@@ -3186,9 +2411,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;
     }
@@ -4178,10 +3409,12 @@ void getmainconfig(const char *configfile) {
                          "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,
@@ -4273,7 +3506,7 @@ void *sighandler(void *arg) {
 }
 
 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;
@@ -4298,8 +3531,6 @@ int main(int argc, char **argv) {
 
     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");
 
@@ -4317,15 +3548,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)) {
-       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)
@@ -4341,6 +3563,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");
@@ -4348,12 +3571,31 @@ int main(int argc, char **argv) {
        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);