diff options
-rw-r--r-- | radsecproxy.c | 255 | ||||
-rw-r--r-- | radsecproxy.h | 2 |
2 files changed, 173 insertions, 84 deletions
diff --git a/radsecproxy.c b/radsecproxy.c index 90a2914..e4eee75 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -68,11 +68,13 @@ static struct options options; struct list *clconfs, *srvconfs, *realms, *tlsconfs, *rewriteconfs; -static struct addrinfo *srcprotores[3] = { NULL, NULL, NULL }; +static struct addrinfo *srcprotores[4] = { NULL, NULL, NULL, 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; @@ -87,6 +89,7 @@ void freerealm(struct realm *realm); void freeclsrvconf(struct clsrvconf *conf); void freerqdata(struct request *rq); void *udpserverrd(void *arg); +void *udpdtlsserverrd(void *arg); void *tlslistener(void *arg); void *tcplistener(void *arg); int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text); @@ -148,15 +151,15 @@ 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 */ - NULL, /* listener */ - &options.sourceudp, /* srcaddrport */ + udpdtlsserverrd, /* listener */ + &options.sourcedtls, /* srcaddrport */ dtlsconnect, /* connecter */ dtlsclientrd, /* clientreader */ clientradputdtls /* clientradput */ @@ -633,10 +636,8 @@ 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); @@ -645,7 +646,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) { @@ -666,9 +668,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) { @@ -709,9 +734,9 @@ int udp2bio(int s, struct queue *q, int cnt) { buf = malloc(cnt); if (!buf) { + unsigned char err; debug(DBG_ERR, "udp2bio: malloc failed"); - /* is this ok? */ - recv(s, NULL, 0, 0); + recv(s, &err, 1, 0); return 0; } @@ -747,7 +772,6 @@ 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) { @@ -763,80 +787,50 @@ unsigned char *radudpget(int s, struct client **client, struct server **server, debug(DBG_WARN, "radudpget: recv failed"); continue; } + if (cnt < 20) { + debug(DBG_WARN, "radudpget: length too small"); + recv(s, buf, 4, 0); + continue; + } - if ((p = find_conf(RAD_UDP, (struct sockaddr *)&from, client ? clconfs : srvconfs, NULL))) { - if (cnt >= 20) - len = RADLEN(buf); - if (cnt < 20 || len < 20) { - debug(DBG_WARN, "radudpget: length too small"); - recv(s, buf, 4, 0); - continue; - } + p = find_conf(RAD_UDP, (struct sockaddr *)&from, client ? clconfs : 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; - } + 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)); + 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"); - continue; - } - - if (cnt > len) - debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len); - } else { - p = find_conf(RAD_DTLS, (struct sockaddr *)&from, client ? clconfs : 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; - } + if (cnt < len) { + debug(DBG_WARN, "radudpget: packet smaller than length field in radius header"); + continue; } - + if (cnt > len) + debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len); + if (client) { node = list_first(p->clients); - switch (p->type) { - case RAD_UDP: - *client = node ? (struct client *)node->data : addclient(p); - if (!*client) - continue; - 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)); + *client = node ? (struct client *)node->data : addclient(p); + if (!*client) 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) @@ -1103,6 +1097,58 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t return 1; } +void *udpdtlsserverrd(void *arg) { + int cnt, s = *(int *)arg; + unsigned char buf[4]; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + struct clsrvconf *conf; + struct list_node *node; + struct client *client; + fd_set readfds; + pthread_t dtlsserverth; + + 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 | MSG_TRUNC, (struct sockaddr *)&from, &fromlen); + if (cnt == -1) { + debug(DBG_WARN, "udpdtlsserverrd: recv failed"); + continue; + } + conf = find_conf(RAD_DTLS, (struct sockaddr *)&from, clconfs, NULL); + if (!conf) { + debug(DBG_WARN, "udpdtlsserverrd: got packet from wrong or unknown DTLS peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen)); + recv(s, buf, 4, 0); + continue; + } + + node = list_first(conf->clients); + if (node) + client = (struct client *)node->data; + else { + client = addclient(conf); + if (!client) { + recv(s, buf, 4, 0); + continue; + } + client->sock = s; + memcpy(&client->addr, &from, fromlen); + if (pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)client)) { + debug(DBG_ERR, "udpdtlsserverrd: pthread_create failed"); + removeclient(client); + recv(s, buf, 4, 0); + continue; + } + pthread_detach(dtlsserverth); + } + if (udp2bio(s, client->rbios, cnt)) + debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen)); + } +} + void *dtlsserverwr(void *arg) { int cnt; unsigned long error; @@ -1378,12 +1424,11 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char * if (!cert) continue; - if (verifyconfcert(cert, server->conf)) { - X509_free(cert); + if (verifyconfcert(cert, server->conf)) break; - } X509_free(cert); } + 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); @@ -2937,6 +2982,36 @@ void *tlsclientrd(void *arg) { return NULL; } +void *udpdtlsclientrd(void *arg) { + int cnt, s = *(int *)arg; + unsigned char buf[4]; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + struct clsrvconf *conf; + 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 | MSG_TRUNC, (struct sockaddr *)&from, &fromlen); + if (cnt == -1) { + debug(DBG_WARN, "udpdtlsclientrd: recv failed"); + continue; + } + + conf = find_conf(RAD_DTLS, (struct sockaddr *)&from, srvconfs, NULL); + if (!conf) { + debug(DBG_WARN, "udpdtlsclientrd: got packet from wrong or unknown DTLS peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen)); + recv(s, buf, 4, 0); + continue; + } + if (udp2bio(s, conf->servers->rbios, cnt)) + debug(DBG_DBG, "radudpget: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen)); + } +} + void *dtlsclientrd(void *arg) { struct server *server = (struct server *)arg; unsigned char *buf; @@ -4588,10 +4663,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, @@ -4683,7 +4760,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; @@ -4748,13 +4825,23 @@ 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_UDP, clconfs, NULL) || find_conf_type(RAD_DTLS, clconfs, NULL)) { + 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, NULL)) debugx(1, DBG_ERR, "pthread_create failed"); diff --git a/radsecproxy.h b/radsecproxy.h index 95506a2..34f56ca 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -46,10 +46,12 @@ struct options { char **listenudp; char **listentcp; char **listentls; + char **listendtls; char **listenaccudp; char *sourceudp; char *sourcetcp; char *sourcetls; + char *sourcedtls; char *logdestination; uint8_t loglevel; uint8_t loopprevention; |