1 diff --git a/ChangeLog b/ChangeLog
2 index c1943fb..d6552db 100644
8 + - Optionally log accounting requests when respoinding directly (#72)
9 + - SNI support for outgoing connections (#90)
12 + - Don't require server type to be set by dyndisc scripts
13 + - OpenSSL 3.0 compatibility (#70)
16 + - Fix refused startup with openssl <1.1 (#82)
17 + - Fix compiler issue for Fedora 33 on s390x (#84)
18 + - Fix small memory leak in config parser
19 + - Fix lazy certificate check when connecting to TLS servers
20 + - Fix connect is aborted if first host in list has invalid certificate
21 + - Fix setstacksize for glibc 2.34 (#91)
25 - Accept multiple source* configs for IPv4/v6
26 diff --git a/README b/README
27 index 20700fa..5074c77 100644
30 @@ -8,11 +8,12 @@ flexible, while at the same time to be small, efficient and easy to configure.
31 Official packages are available:
33 Debian: apt-get install radsecproxy
34 +CentOS/RHEL/Rocky: yum install epel-release; yum install radsecproxy
35 Fedora: dnf install radsecproxy
36 FreeBSD: pkg install radsecproxy
37 NetBSD: pkgin install radsecproxy
39 -Or built it from this rouce on most Unix like systems by simply typing
40 +Or built it from this source on most Unix like systems by simply typing
44 diff --git a/configure.ac b/configure.ac
45 index 630fcac..d486e47 100644
48 @@ -11,6 +11,12 @@ AC_PROG_RANLIB
49 AC_CHECK_FUNCS([mallopt])
50 AC_REQUIRE_AUX_FILE([tap-driver.sh])
52 +m4_version_prereq(2.70, [], [AC_PROG_CC_C99])
53 +if test "$ac_cv_prog_cc_c99" = "no"; then
54 + echo "requires C99 compatible compiler"
60 [ --enable-udp whether to enable UDP transport: yes/no; default yes ],
61 diff --git a/dtls.c b/dtls.c
62 index 09aa9ee..15835d6 100644
65 @@ -142,6 +142,7 @@ int dtlsread(SSL *ssl, unsigned char *buf, int num, int timeout, pthread_mutex_t
67 case SSL_ERROR_ZERO_RETURN:
68 debug(DBG_DBG, "dtlsread: got ssl shutdown");
71 while ((error = ERR_get_error()))
72 debug(DBG_ERR, "dtlsread: SSL: %s", ERR_error_string(error, NULL));
73 @@ -305,10 +306,11 @@ void *dtlsservernew(void *arg) {
74 struct timeval timeout;
75 struct addrinfo tmpsrvaddr;
76 char tmp[INET6_ADDRSTRLEN], *subj;
77 + struct hostportres *hp;
79 debug(DBG_WARN, "dtlsservernew: incoming DTLS connection from %s", addr2string((struct sockaddr *)¶ms->addr, tmp, sizeof(tmp)));
81 - conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, NULL);
82 + conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, NULL, &hp);
86 @@ -342,7 +344,7 @@ void *dtlsservernew(void *arg) {
87 accepted_tls = conf->tlsconf;
90 - if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf)) {
91 + if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf, NULL)) {
92 subj = getcertsubject(cert);
94 debug(DBG_WARN, "dtlsservernew: DTLS connection from %s, client %s, subject %s up",
95 @@ -362,9 +364,10 @@ void *dtlsservernew(void *arg) {
99 - conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, &cur);
100 + conf = find_clconf(handle, (struct sockaddr *)¶ms->addr, &cur, &hp);
102 - debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client");
103 + debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client for %s",
104 + addr2string((struct sockaddr *)¶ms->addr, tmp, sizeof(tmp)));
108 @@ -467,7 +470,7 @@ void *dtlslistener(void *arg) {
112 - conf = find_clconf(handle, (struct sockaddr *)&from, NULL);
113 + conf = find_clconf(handle, (struct sockaddr *)&from, NULL, NULL);
115 debug(DBG_INFO, "dtlslistener: got UDP from unknown peer %s, ignoring", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
116 if (recv(s, buf, 4, 0) == -1)
117 @@ -486,6 +489,7 @@ void *dtlslistener(void *arg) {
120 pthread_mutex_unlock(&conf->tlsconf->lock);
121 + debug(DBG_ERR, "dtlslistener: failed to create SSL connection");
124 bio = BIO_new_dgram(s, BIO_NOCLOSE);
125 @@ -514,12 +518,28 @@ void *dtlslistener(void *arg) {
130 + unsigned long error;
131 + while ((error = ERR_get_error()))
132 + debug(DBG_ERR, "dtlslistener: DTLS_listen failed: %s", ERR_error_string(error, NULL));
133 + debug(DBG_ERR, "dtlslistener: DTLS_listen failed from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
135 pthread_mutex_unlock(&conf->tlsconf->lock);
140 +static void cleanup_connection(struct server *server) {
142 + SSL_shutdown(server->ssl);
143 + if (server->sock >= 0)
144 + close(server->sock);
147 + SSL_free(server->ssl);
148 + server->ssl = NULL;
151 int dtlsconnect(struct server *server, int timeout, char *text) {
152 struct timeval socktimeout, now, start;
154 @@ -531,6 +551,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
156 struct addrinfo *source = NULL;
158 + struct list_node *entry;
160 debug(DBG_DBG, "dtlsconnect: called from %s", text);
161 pthread_mutex_lock(&server->lock);
162 @@ -540,8 +561,6 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
164 pthread_mutex_unlock(&server->lock);
166 - hp = (struct hostportres *)list_first(server->conf->hostports)->data;
168 if(server->conf->source) {
169 source = resolvepassiveaddrinfo(server->conf->source, AF_UNSPEC, NULL, protodefs.socktype);
171 @@ -552,13 +571,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
174 /* ensure previous connection is properly closed */
176 - SSL_shutdown(server->ssl);
177 - if (server->sock >= 0)
178 - close(server->sock);
180 - SSL_free(server->ssl);
181 - server->ssl = NULL;
182 + cleanup_connection(server);
184 wait = connect_wait(start, server->connecttime, firsttry);
185 gettimeofday(&now, NULL);
186 @@ -567,55 +580,84 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
187 if (source) freeaddrinfo(source);
190 - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
191 + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
195 - debug(DBG_INFO, "dtlsconnect: connecting to %s port %s", hp->host, hp->port);
196 + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
197 + hp = (struct hostportres *)entry->data;
198 + debug(DBG_INFO, "dtlsconnect: trying to open DTLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
199 + if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0) {
200 + debug(DBG_ERR, "dtlsconnect: faild to bind socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port);
203 + if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen)) {
204 + debug(DBG_ERR, "dtlsconnect: faild to connect socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port);
208 - if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0)
210 - if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen))
212 + pthread_mutex_lock(&server->conf->tlsconf->lock);
213 + if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
214 + pthread_mutex_unlock(&server->conf->tlsconf->lock);
215 + debug(DBG_ERR, "dtlsconnect: failed to get TLS context for server %s", server->conf->name);
219 - pthread_mutex_lock(&server->conf->tlsconf->lock);
220 - if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
221 + server->ssl = SSL_new(ctx);
222 pthread_mutex_unlock(&server->conf->tlsconf->lock);
225 + if (!server->ssl) {
226 + debug(DBG_ERR, "dtlsconnect: failed to create SSL conneciton for server %s", server->conf->name);
230 - server->ssl = SSL_new(ctx);
231 - pthread_mutex_unlock(&server->conf->tlsconf->lock);
234 + if (server->conf->sni) {
235 + struct in6_addr tmp;
236 + char *servername = server->conf->sniservername ? server->conf->sniservername :
237 + (inet_pton(AF_INET, hp->host, &tmp) || inet_pton(AF_INET6, hp->host, &tmp)) ? NULL : hp->host;
238 + if (servername && !tlssetsni(server->ssl, servername)) {
239 + debug(DBG_ERR, "tlsconnect: set SNI %s failed", servername);
244 - bio = BIO_new_dgram(server->sock, BIO_CLOSE);
245 - BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr);
246 - SSL_set_bio(server->ssl, bio, bio);
247 - if (sslconnecttimeout(server->ssl, 5) <= 0) {
248 - while ((error = ERR_get_error()))
249 - debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
250 - debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed", server->conf->name);
253 - socktimeout.tv_sec = 5;
254 - socktimeout.tv_usec = 0;
255 - if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1)
256 - debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed");
257 + bio = BIO_new_dgram(server->sock, BIO_CLOSE);
258 + BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr);
259 + SSL_set_bio(server->ssl, bio, bio);
260 + if (sslconnecttimeout(server->ssl, 5) <= 0) {
261 + while ((error = ERR_get_error()))
262 + debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
263 + debug(DBG_ERR, "dtlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port);
266 + socktimeout.tv_sec = 5;
267 + socktimeout.tv_usec = 0;
268 + if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1)
269 + debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed");
271 + cert = verifytlscert(server->ssl);
273 + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
277 - cert = verifytlscert(server->ssl);
280 - if (verifyconfcert(cert, server->conf)) {
281 - subj = getcertsubject(cert);
283 - debug(DBG_WARN, "dtlsconnect: DTLS connection to %s, subject %s up", server->conf->name, subj);
285 + if (verifyconfcert(cert, server->conf, hp)) {
286 + subj = getcertsubject(cert);
288 + debug(DBG_WARN, "dtlsconnect: DTLS connection to %s (%s port %s), subject %s up", server->conf->name, hp->host, hp->port, subj);
294 + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
300 + /* ensure previous connection is properly closed */
301 + cleanup_connection(server);
304 + if (server->ssl) break;
307 pthread_mutex_lock(&server->lock);
308 diff --git a/hostport.c b/hostport.c
309 index 6408505..d0651d4 100644
312 @@ -222,7 +222,7 @@ int resolvehostports(struct list *hostports, int af, int socktype) {
315 struct addrinfo *resolvepassiveaddrinfo(char **hostport, int af, char *default_port, int socktype) {
316 - struct addrinfo *ai = NULL, *last_ai;
317 + struct addrinfo *ai = NULL, *last_ai = NULL;
319 char *any[2] = {"*", NULL};
321 @@ -258,7 +258,7 @@ static int prefixmatch(void *a1, void *a2, uint8_t len) {
322 return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
325 -int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t prefixlen, uint8_t checkport) {
326 +int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t prefixlen, uint8_t checkport, struct hostportres **hpreturn) {
327 struct sockaddr_in6 *sa6 = NULL;
328 struct in_addr *a4 = NULL;
329 struct addrinfo *res;
330 @@ -287,16 +287,20 @@ int _internal_addressmatches(struct list *hostports, struct sockaddr *addr, uint
331 !memcmp(&sa6->sin6_addr,
332 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16) &&
333 (!checkport || ((struct sockaddr_in6 *)res->ai_addr)->sin6_port ==
334 - ((struct sockaddr_in6 *)addr)->sin6_port)))
335 + ((struct sockaddr_in6 *)addr)->sin6_port))) {
337 + if (hpreturn) *hpreturn = hp;
340 } else if (hp->prefixlen <= prefixlen) {
341 if ((a4 && res->ai_family == AF_INET &&
342 prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, hp->prefixlen)) ||
343 (sa6 && res->ai_family == AF_INET6 &&
344 - prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, hp->prefixlen)))
345 + prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, hp->prefixlen))) {
347 + if (hpreturn) *hpreturn = hp;
353 @@ -312,18 +316,18 @@ int hostportmatches(struct list *hostports, struct list *matchhostports, uint8_t
354 match = (struct hostportres *)entry->data;
356 for (res = match->addrinfo; res; res = res->ai_next) {
357 - if (_internal_addressmatches(hostports, res->ai_addr, match->prefixlen, checkport))
358 + if (_internal_addressmatches(hostports, res->ai_addr, match->prefixlen, checkport, NULL))
365 -int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport) {
366 - return _internal_addressmatches(hostports, addr, 255, checkport);
367 +int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport, struct hostportres **hp) {
368 + return _internal_addressmatches(hostports, addr, 255, checkport, hp);
371 -int connecttcphostlist(struct list *hostports, struct addrinfo *src) {
372 +int connecttcphostlist(struct list *hostports, struct addrinfo *src, struct hostportres** hpreturn) {
374 struct list_node *entry;
375 struct hostportres *hp = NULL;
376 @@ -333,6 +337,7 @@ int connecttcphostlist(struct list *hostports, struct addrinfo *src) {
377 debug(DBG_WARN, "connecttcphostlist: trying to open TCP connection to %s port %s", hp->host, hp->port);
378 if ((s = connecttcp(hp->addrinfo, src, list_count(hostports) > 1 ? 5 : 30)) >= 0) {
379 debug(DBG_WARN, "connecttcphostlist: TCP connection to %s port %s up", hp->host, hp->port);
380 + if (hpreturn) *hpreturn = hp;
384 diff --git a/hostport.h b/hostport.h
385 index 9069ecd..a554a77 100644
389 * Copyright (c) 2012, NORDUnet A/S */
390 /* See LICENSE for licensing information. */
398 @@ -17,9 +20,10 @@ int resolvehostport(struct hostportres *hp, int af, int socktype, uint8_t passiv
399 int resolvehostports(struct list *hostports, int af, int socktype);
400 struct addrinfo *resolvepassiveaddrinfo(char **hostport, int af, char *default_port, int socktype);
401 int hostportmatches(struct list *hostports, struct list *matchhostports, uint8_t checkport);
402 -int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport);
403 -int connecttcphostlist(struct list *hostports, struct addrinfo *src);
404 +int addressmatches(struct list *hostports, struct sockaddr *addr, uint8_t checkport, struct hostportres **hp);
405 +int connecttcphostlist(struct list *hostports, struct addrinfo *src, struct hostportres **hpreturn);
407 +#endif /* _HOSTPORT_H */
408 /* Local Variables: */
409 /* c-file-style: "stroustrup" */
411 diff --git a/list.h b/list.h
412 index f015b9d..c8c4531 100644
415 @@ -35,7 +35,7 @@ int list_push(struct list *list, void *data);
416 /* removes first entry from list and returns data */
417 void *list_shift(struct list *list);
419 -/* removes first entry with matching data pointer */
420 +/* removes all entries with matching data pointer */
421 void list_removedata(struct list *list, void *data);
423 /* returns first node */
424 diff --git a/raddict.h b/raddict.h
426 index 0000000..8a9c598
433 +const char* RAD_Attr_Acct_Terminate_Cause_Dict[] = {
434 + [1] = "User-Request",
448 + "Service-Unavailable",
454 +const char* RAD_Attr_Acct_Status_Type_Dict[] = {
457 + [3] = "Interim-Update",
458 + [7] = "Accounting-On",
459 + [8] = "Accounting-Off",
460 + [9] = "Tunnel-Start",
461 + [10] = "Tunnel-Stop",
462 + [11] = "Tunnel-Reject",
463 + [12] = "Tunnel-Link-Start",
464 + [13] = "Tunnel-Link-Stop",
465 + [14] = "Tunnel-Link-Reject",
469 +#define RAD_Attr_Dict_Undef "UNKNOWN"
471 +#endif /*_RADDICT_H*/
472 diff --git a/radmsg.c b/radmsg.c
473 index 5f49237..afd7c60 100644
478 #include <nettle/hmac.h>
479 #include <openssl/rand.h>
480 +#include "raddict.h"
483 #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
485 @@ -414,6 +416,28 @@ int resizeattr(struct tlv *attr, uint8_t newlen) {
489 +const char* attrval2strdict(struct tlv *attr) {
492 + if(!attr) return NULL;
493 + val = tlv2longint(attr);
495 + case RAD_Attr_Acct_Status_Type:
496 + if(val < sizeof(RAD_Attr_Acct_Status_Type_Dict)/sizeof(RAD_Attr_Acct_Status_Type_Dict[0]))
497 + return RAD_Attr_Acct_Status_Type_Dict[val] ? RAD_Attr_Acct_Status_Type_Dict[val] : RAD_Attr_Dict_Undef;
500 + case RAD_Attr_Acct_Terminate_Cause:
501 + if(val < sizeof(RAD_Attr_Acct_Terminate_Cause_Dict)/sizeof(RAD_Attr_Acct_Terminate_Cause_Dict[0]))
502 + return RAD_Attr_Acct_Terminate_Cause_Dict[val] ? RAD_Attr_Acct_Terminate_Cause_Dict[val] : RAD_Attr_Dict_Undef;
511 /* Local Variables: */
512 /* c-file-style: "stroustrup" */
514 diff --git a/radmsg.h b/radmsg.h
515 index 1738c8e..634cf13 100644
519 #define RAD_Attr_User_Name 1
520 #define RAD_Attr_User_Password 2
521 #define RAD_Attr_CHAP_Password 3
522 +#define RAD_Attr_NAS_IP_Address 4
523 +#define RAD_Attr_Framed_IP_Address 8
524 #define RAD_Attr_Reply_Message 18
525 #define RAD_Attr_Vendor_Specific 26
526 +#define RAD_Attr_Called_Station_Id 30
527 #define RAD_Attr_Calling_Station_Id 31
528 #define RAD_Attr_Proxy_State 33
529 +#define RAD_Attr_Acct_Status_Type 40
530 +#define RAD_Attr_Acct_Input_Octets 42
531 +#define RAD_Attr_Acct_Output_Octets 43
532 +#define RAD_Attr_Acct_Session_Id 44
533 +#define RAD_Attr_Acct_Session_Time 46
534 +#define RAD_Attr_Acct_Input_Packets 47
535 +#define RAD_Attr_Acct_Output_Packets 48
536 +#define RAD_Attr_Acct_Terminate_Cause 49
537 +#define RAD_Attr_Event_Timestamp 55
538 #define RAD_Attr_CHAP_Challenge 60
539 #define RAD_Attr_Tunnel_Password 69
540 #define RAD_Attr_Message_Authenticator 80
541 #define RAD_Attr_CUI 89
542 #define RAD_Attr_Operator_Name 126
544 +#define RAD_Acct_Status_Start 1
545 +#define RAD_Acct_Status_Stop 2
546 +#define RAD_Acct_Status_Alive 3
547 +#define RAD_Acct_Status_Interim_Update 3
548 +#define RAD_Acct_Status_Accounting_On 7
549 +#define RAD_Acct_Status_Accounting_Off 8
550 +#define RAD_Acct_Status_Failed 15
553 #define RAD_VS_ATTR_MS_MPPE_Send_Key 16
554 #define RAD_VS_ATTR_MS_MPPE_Recv_Key 17
556 @@ -63,6 +84,16 @@ int attrvalidate(unsigned char *attrs, int length);
557 struct tlv *makevendortlv(uint32_t vendor, struct tlv *attr);
558 int resizeattr(struct tlv *attr, uint8_t newlen);
561 + * convert the attribute value to its string representation form the dictionary
564 + * @param attr the attribute to convert
565 + * @return the string representation or NULL, if the attribute/value is not in the
568 +const char* attrval2strdict(struct tlv *attr);
572 /* Local Variables: */
573 diff --git a/radsecproxy.c b/radsecproxy.c
574 index c755acb..75f5ef3 100644
577 @@ -121,13 +121,13 @@ int prefixmatch(void *a1, void *a2, uint8_t len) {
580 /* returns next config with matching address, or NULL */
581 -struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur, uint8_t server_p) {
582 +struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur, uint8_t server_p, struct hostportres **hp) {
583 struct list_node *entry;
584 struct clsrvconf *conf;
586 for (entry = (cur && *cur ? list_next(*cur) : list_first(confs)); entry; entry = list_next(entry)) {
587 conf = (struct clsrvconf *)entry->data;
588 - if (conf->type == type && addressmatches(conf->hostports, addr, server_p)) {
589 + if (conf->type == type && addressmatches(conf->hostports, addr, server_p, hp)) {
593 @@ -136,12 +136,12 @@ struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *co
597 -struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
598 - return find_conf(type, addr, clconfs, cur, 0);
599 +struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur, struct hostportres **hp) {
600 + return find_conf(type, addr, clconfs, cur, 0, hp);
603 struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
604 - return find_conf(type, addr, srvconfs, cur, 1);
605 + return find_conf(type, addr, srvconfs, cur, 1, NULL);
608 /* returns next config of given type, or NULL */
609 @@ -1241,6 +1241,49 @@ void rmclientrq(struct request *rq, uint8_t id) {
613 +static void log_accounting_resp(struct client *from, struct radmsg *msg, char *user) {
614 + char tmp[INET6_ADDRSTRLEN];
615 + const char* status_type = attrval2strdict(radmsg_gettype(msg, RAD_Attr_Acct_Status_Type));
616 + char* nas_ip_address = tlv2ipv4addr(radmsg_gettype(msg, RAD_Attr_NAS_IP_Address));
617 + char* framed_ip_address = tlv2ipv4addr(radmsg_gettype(msg, RAD_Attr_Framed_IP_Address));
619 + time_t event_timestamp_i = tlv2longint(radmsg_gettype(msg, RAD_Attr_Event_Timestamp));
620 + char event_timestamp[32]; /* timestamp should be at most 21 bytes, leave a few spare */
622 + uint8_t *session_id = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Acct_Session_Id));
623 + uint8_t *called_station_id = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Called_Station_Id));
624 + uint8_t *calling_station_id = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Calling_Station_Id));
625 + const char* terminate_cause = attrval2strdict(radmsg_gettype(msg, RAD_Attr_Acct_Terminate_Cause));
627 + strftime(event_timestamp, sizeof(event_timestamp), "%FT%TZ", gmtime(&event_timestamp_i));
629 + debug(DBG_NOTICE, "Accounting %s (id %d) at %s from client %s (%s): { SID=%s, User-Name=%s, Ced-S-Id=%s, Cing-S-Id=%s, NAS-IP=%s, Framed-IP=%s, Sess-Time=%u, In-Packets=%u, In-Octets=%u, Out-Packets=%u, Out-Octets=%u, Terminate-Cause=%s }",
630 + status_type ? status_type : "UNKNOWN",
632 + event_timestamp_i ? event_timestamp : "UNKNOWN",
634 + addr2string(from->addr, tmp, sizeof(tmp)),
636 + session_id ? session_id : (uint8_t*)"",
638 + called_station_id ? called_station_id : (uint8_t*)"",
639 + calling_station_id ? calling_station_id : (uint8_t*)"",
640 + nas_ip_address ? nas_ip_address : "0.0.0.0",
641 + framed_ip_address ? framed_ip_address : "0.0.0.0",
642 + tlv2longint(radmsg_gettype(msg, RAD_Attr_Acct_Session_Time)),
643 + tlv2longint(radmsg_gettype(msg, RAD_Attr_Acct_Input_Packets)),
644 + tlv2longint(radmsg_gettype(msg, RAD_Attr_Acct_Input_Octets)),
645 + tlv2longint(radmsg_gettype(msg, RAD_Attr_Acct_Output_Packets)),
646 + tlv2longint(radmsg_gettype(msg, RAD_Attr_Acct_Output_Octets)),
647 + terminate_cause ? terminate_cause : ""
649 + free(framed_ip_address);
650 + free(nas_ip_address);
652 + free(called_station_id);
653 + free(calling_station_id);
656 /* Called from server readers, handling incoming requests from
658 /* returns 0 if validation/authentication fails, else 1 */
659 @@ -1321,13 +1364,15 @@ int radsrv(struct request *rq) {
663 - if (realm->message && msg->code == RAD_Access_Request) {
664 - debug(DBG_INFO, "radsrv: sending %s (id %d) to %s (%s) for %s", radmsgtype2string(RAD_Access_Reject), msg->id, from->conf->name, addr2string(from->addr, tmp, sizeof(tmp)), userascii);
665 - respond(rq, RAD_Access_Reject, realm->message, 1, 1);
666 - } else if (realm->accresp && msg->code == RAD_Accounting_Request) {
667 - respond(rq, RAD_Accounting_Response, NULL, 1, 0);
670 + if (realm->message && msg->code == RAD_Access_Request) {
671 + debug(DBG_INFO, "radsrv: sending %s (id %d) to %s (%s) for %s", radmsgtype2string(RAD_Access_Reject), msg->id, from->conf->name, addr2string(from->addr, tmp, sizeof(tmp)), userascii);
672 + respond(rq, RAD_Access_Reject, realm->message, 1, 1);
673 + } else if (realm->accresp && msg->code == RAD_Accounting_Request) {
675 + log_accounting_resp(from, msg, (char *)userascii);
676 + respond(rq, RAD_Accounting_Response, NULL, 1, 0);
681 if ((to->conf->loopprevention == 1
682 @@ -1592,7 +1637,7 @@ void *clientwr(void *arg) {
683 if (server->dynamiclookuparg && !dynamicconfig(server)) {
685 server->state = RSP_SERVER_STATE_FAILING;
686 - debug(DBG_WARN, "%s: dynamicconfig(%s: %s) failed, sleeping %ds",
687 + debug(DBG_WARN, "%s: dynamicconfig(%s: %s) failed, Not trying again for %ds",
688 __func__, server->conf->name, server->dynamiclookuparg, ZZZ);
691 @@ -1600,7 +1645,7 @@ void *clientwr(void *arg) {
692 * either as part of static configuration setup or by
693 * dynamicconfig() above? */
694 if (!resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) {
695 - debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ);
696 + debug(DBG_WARN, "%s: resolve failed, Not trying again for %ds", __func__, ZZZ);
697 server->state = RSP_SERVER_STATE_FAILING;
700 @@ -1615,7 +1660,7 @@ void *clientwr(void *arg) {
701 if (!conf->pdef->connecter(server, server->dynamiclookuparg ? 5 : 0, "clientwr")) {
702 server->state = RSP_SERVER_STATE_FAILING;
703 if (server->dynamiclookuparg) {
704 - debug(DBG_WARN, "%s: connect failed, sleeping %ds", __func__, ZZZ);
705 + debug(DBG_WARN, "%s: connect failed, giving up. Not trying again for %ds", __func__, ZZZ);
709 @@ -1927,7 +1972,7 @@ void freerealm(struct realm *realm) {
713 -struct realm *addrealm(struct list *realmlist, char *value, char **servers, char **accservers, char *message, uint8_t accresp) {
714 +struct realm *addrealm(struct list *realmlist, char *value, char **servers, char **accservers, char *message, uint8_t accresp, uint8_t acclog) {
717 char *s, *regex = NULL;
718 @@ -1991,6 +2036,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char
720 realm->message = message;
721 realm->accresp = accresp;
722 + realm->acclog = acclog;
724 if (regcomp(&realm->regex, regex ? regex : value + 1, REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
725 debug(DBG_ERR, "addrealm: failed to compile regular expression %s", regex ? regex : value + 1);
726 @@ -2111,7 +2157,7 @@ struct realm *adddynamicrealmserver(struct realm *realm, char *id) {
727 if (!realm->subrealms)
730 - newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, stringcopy(realm->message, 0), realm->accresp);
731 + newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, stringcopy(realm->message, 0), realm->accresp, realm->acclog);
733 list_destroy(realm->subrealms);
734 realm->subrealms = NULL;
735 @@ -2223,6 +2269,7 @@ void freeclsrvconf(struct clsrvconf *conf) {
736 freematchcertattr(conf);
737 free(conf->confrewritein);
738 free(conf->confrewriteout);
739 + free(conf->sniservername);
740 if (conf->rewriteusername) {
741 if (conf->rewriteusername->regex)
742 regfree(conf->rewriteusername->regex);
743 @@ -2316,7 +2363,8 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
744 !mergeconfstring(&dst->confrewriteusername, &src->confrewriteusername) ||
745 !mergeconfstring(&dst->dynamiclookupcommand, &src->dynamiclookupcommand) ||
746 !mergeconfstring(&dst->fticks_viscountry, &src->fticks_viscountry) ||
747 - !mergeconfstring(&dst->fticks_visinst, &src->fticks_visinst))
748 + !mergeconfstring(&dst->fticks_visinst, &src->fticks_visinst) ||
749 + !mergeconfstring(&dst->sniservername, &src->sniservername))
752 dst->pdef = src->pdef;
753 @@ -2327,6 +2375,7 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
754 if (src->retrycount != 255)
755 dst->retrycount = src->retrycount;
756 dst->blockingstartup = src->blockingstartup;
757 + dst->sni = src->sni;
761 @@ -2416,7 +2465,7 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
762 ? tlsgettls(conf->tls, NULL)
763 : tlsgettls("defaultClient", "default");
765 - debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
766 + debugx(1, DBG_ERR, "error in block %s, tls context not defined", block);
767 if (matchcertattrs) {
768 for (i=0; matchcertattrs[i]; i++){
769 if (!addmatchcertattr(conf, matchcertattrs[i])) {
770 @@ -2485,7 +2534,7 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
771 existing->tlsconf != conf->tlsconf &&
772 hostportmatches(existing->hostports, conf->hostports, 0)) {
774 - debugx(1, DBG_ERR, "error in block %s, overlapping clients must reference the same tls block", block);
775 + debugx(1, DBG_ERR, "error in block %s, masked by overlapping (equal or less specific IP/prefix) client %s with different tls block", block, existing->name);
779 @@ -2573,8 +2622,12 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
781 conf->statusserver = resconf->statusserver;
782 conf->certnamecheck = resconf->certnamecheck;
783 + conf->blockingstartup = resconf->blockingstartup;
784 + conf->type = resconf->type;
785 + conf->sni = resconf->sni;
787 conf->certnamecheck = 1;
788 + conf->sni = options.sni;
791 if (!getgenericconfig(cf, block,
792 @@ -2601,6 +2654,8 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
793 "DynamicLookupCommand", CONF_STR, &conf->dynamiclookupcommand,
794 "LoopPrevention", CONF_BLN, &conf->loopprevention,
795 "BlockingStartup", CONF_BLN, &conf->blockingstartup,
796 + "SNI", CONF_BLN, &conf->sni,
797 + "SNIservername", CONF_STR, &conf->sniservername,
800 debug(DBG_ERR, "configuration error");
801 @@ -2621,16 +2676,20 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
805 - debug(DBG_ERR, "error in block %s, option type missing", block);
808 - conf->type = protoname2int(conftype);
809 - if (conf->type == 255) {
810 - debug(DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
813 + debug(DBG_ERR, "error in block %s, option type missing", block);
817 + conf->type = protoname2int(conftype);
818 + if (conf->type == 255) {
819 + debug(DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
824 + conf->pdef = protodefs[conf->type];
829 conf->hostaf = AF_UNSPEC;
830 if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
831 @@ -2638,8 +2697,6 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
832 if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
835 - conf->pdef = protodefs[conf->type];
837 if (!conf->confrewritein)
838 conf->confrewritein = rewriteinalias;
840 @@ -2683,8 +2740,12 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
841 conf->statusserver = RSP_STATSRV_AUTO;
843 debugx(1, DBG_ERR, "config error in blocck %s: invalid StatusServer value: %s", block, statusserver);
844 + free(statusserver);
847 + if(conf->sniservername)
851 if (!mergesrvconf(resconf, conf))
853 @@ -2769,7 +2830,7 @@ int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, cha
855 int confrealm_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
856 char **servers = NULL, **accservers = NULL, *msg = NULL;
857 - uint8_t accresp = 0;
858 + uint8_t accresp = 0, acclog = 0;
860 debug(DBG_DBG, "confrealm_cb called for %s", block);
862 @@ -2778,11 +2839,12 @@ int confrealm_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
863 "accountingServer", CONF_MSTR, &accservers,
864 "ReplyMessage", CONF_STR, &msg,
865 "AccountingResponse", CONF_BLN, &accresp,
866 + "AccountingLog", CONF_BLN, &acclog,
869 debugx(1, DBG_ERR, "configuration error");
871 - addrealm(realms, val, servers, accservers, msg, accresp);
872 + addrealm(realms, val, servers, accservers, msg, accresp, acclog);
876 @@ -2871,6 +2933,7 @@ void getmainconfig(const char *configfile) {
877 "FTicksPrefix", CONF_STR, &options.fticksprefix,
878 "IPv4Only", CONF_BLN, &options.ipv4only,
879 "IPv6Only", CONF_BLN, &options.ipv6only,
880 + "SNI", CONF_BLN, &options.sni,
883 debugx(1, DBG_ERR, "configuration error");
884 @@ -3031,6 +3094,7 @@ int createpidfile(const char *pidfile) {
885 int radsecproxy_main(int argc, char **argv) {
889 struct list_node *entry;
890 uint8_t foreground = 0, pretend = 0, loglevel = 0;
891 char *configfile = NULL, *pidfile = NULL;
892 @@ -3042,8 +3106,13 @@ int radsecproxy_main(int argc, char **argv) {
894 if (pthread_attr_init(&pthread_attr))
895 debugx(1, DBG_ERR, "pthread_attr_init failed");
896 - if (pthread_attr_setstacksize(&pthread_attr, PTHREAD_STACK_SIZE))
897 - debugx(1, DBG_ERR, "pthread_attr_setstacksize failed");
898 +#if defined(PTHREAD_STACK_MIN)
899 + stacksize = THREAD_STACK_SIZE > PTHREAD_STACK_MIN ? THREAD_STACK_SIZE : PTHREAD_STACK_MIN;
901 + stacksize = THREAD_STACK_SIZE;
903 + if (pthread_attr_setstacksize(&pthread_attr, stacksize))
904 + debug(DBG_WARN, "pthread_attr_setstacksize failed! Using system default. Memory footprint might be increased!");
905 #if defined(HAVE_MALLOPT)
906 if (mallopt(M_TRIM_THRESHOLD, 4 * 1024) != 1)
907 debugx(1, DBG_ERR, "mallopt failed");
908 diff --git a/radsecproxy.conf-example b/radsecproxy.conf-example
909 index 1730e55..3b2dd64 100644
910 --- a/radsecproxy.conf-example
911 +++ b/radsecproxy.conf-example
912 @@ -203,6 +203,8 @@ server radius.example.com {
913 # statusserver is optional, can be on or off. Off is default
915 # tcp and tls connections also support TCP keepalives.
916 +# Optionally specify the SNI for the outgoing connection
917 +# sni www.example.com
919 #server radius.example.com {
921 diff --git a/radsecproxy.conf.5.in b/radsecproxy.conf.5.in
922 index 87482c1..ebedd6c 100644
923 --- a/radsecproxy.conf.5.in
924 +++ b/radsecproxy.conf.5.in
925 @@ -297,6 +297,15 @@ clients and servers. At most one of IPv4Only and IPv6Only can be enabled.
926 Note that this can be overridden in client and server blocks, see below.
929 +.BR "SNI (" on | off )
931 +Server Name Indication (SNI) is an extension to the TLS protocol. It allows a
932 +client to indicate which hostname it is trying to connect to at the start of
933 +the TLS handshake. Enabling this will use the extension for all TLS and DTLS
934 +servers which specify a hostname (not IP address). This can be overridden in
935 +server blocks, see below.
940 This is not a normal configuration option; it can be specified multiple times.
941 @@ -350,10 +359,11 @@ this might mask clients defined later, which then will never be matched.
943 In the case of TLS/DTLS, the name of the client must match the FQDN or IP
944 address in the client certificate (CN or SubectAltName:DNS or SubjectAltName:IP
945 -respectively). Note that this is not required when the client name is an IP
946 -prefix. If overlapping clients are defined (see section above), they will be
947 -searched for matching \fBMatchCertificateAttribute\fR, but they must reference
949 +respectively) and any \fBMatchCertificateAttribute\fR to be positively identified.
950 +Note that no FQDN/IP is checked when using an IP prefix.
951 +If overlapping clients are defined (see section above), they will be searched for
952 +positive identification, but only among clients referencing the same tls block
953 +(selected by the first matching IP address or prefix).
955 The allowed options in a client block are:
957 @@ -620,6 +630,19 @@ Warning: when the dynamic lookup and connection process is slow, this wil block
958 respective realm for that time.
961 +.BR "SNI (" on | off )
964 +Override gobal SNI setting (see above). This is implicitly enabled if \fBSNIservername\fR
968 +.BI "SNIservername " sni
970 +Explicitly set the \fIsni\fR to request from the server, in case the server is specified
971 +by IP address or to override the hostname. Implicitly enables \fBSNI\fR for this server.
974 The meaning and syntax of the following options are exactly the same as for the client
975 block. The details are not repeated here. Please refer to the definitions in the \fBCLIENT BLOCK\fR section.
977 @@ -679,6 +702,12 @@ Enable sending Accounting-Response instead of ignoring Accounting-Requests when
978 no \fBaccoutingServer\fR are configured.
981 +.BR "AccountingLog (" on | off )
983 +When responding to Accounting-Requests (\fBAccountingResponse on\fR), log the
987 .BI "ReplyMessage " message
989 Specify a message to be sent back to the client if a Access-Request is denied
990 @@ -852,7 +881,8 @@ for DTLS.
993 DH parameter \fIfile\fR to use. See \fBopenssl-dhparam\fR(1)
996 +Note: starting with OpenSSL 3.0, use of custom DH parameters is discouraged.
1000 diff --git a/radsecproxy.h b/radsecproxy.h
1001 index cf493b4..8844415 100644
1006 #include "gconfig.h"
1007 #include "rewrite.h"
1008 +#include "hostport.h"
1010 #include <openssl/asn1.h>
1013 #define STATUS_SERVER_PERIOD 25
1014 #define IDLE_TIMEOUT 300
1016 -/* We want PTHREAD_STACK_SIZE to be 32768, but some platforms
1017 - * have a higher minimum value defined in PTHREAD_STACK_MIN. */
1018 -#define PTHREAD_STACK_SIZE 32768
1019 -#if defined(PTHREAD_STACK_MIN)
1020 -#if PTHREAD_STACK_MIN > PTHREAD_STACK_SIZE
1021 -#undef PTHREAD_STACK_SIZE
1022 -#define PTHREAD_STACK_SIZE PTHREAD_STACK_MIN
1025 +/* Target value for stack size.
1026 + * Some platforms might define higher minimums in PTHREAD_STACK_MIN. */
1027 +#define THREAD_STACK_SIZE 32768
1029 /* For systems that only support RFC 2292 Socket API, but not RFC 3542
1031 @@ -103,6 +98,7 @@ struct options {
1032 uint8_t *fticks_key;
1038 struct commonprotoopts {
1039 @@ -176,6 +172,8 @@ struct clsrvconf {
1040 struct server *servers;
1041 char *fticks_viscountry;
1042 char *fticks_visinst;
1044 + char *sniservername;
1047 #include "tlscommon.h"
1048 @@ -216,6 +214,7 @@ struct realm {
1055 pthread_mutex_t refmutex;
1056 @@ -250,7 +249,7 @@ struct protodefs {
1058 #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
1060 -struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur);
1061 +struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur, struct hostportres **hp);
1062 struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur);
1063 struct clsrvconf *find_clconf_type(uint8_t type, struct list_node **cur);
1064 struct client *addclient(struct clsrvconf *conf, uint8_t lock);
1065 diff --git a/tcp.c b/tcp.c
1066 index ffb2f4c..e148ed0 100644
1070 #include <pthread.h>
1071 #include "radsecproxy.h"
1072 #include "hostport.h"
1077 @@ -84,6 +85,8 @@ int tcpconnect(struct server *server, int timeout, char *text) {
1080 struct addrinfo *source = NULL;
1081 + struct list_node *entry;
1082 + struct hostportres *hp;
1084 debug(DBG_DBG, "tcpconnect: called from %s", text);
1085 pthread_mutex_lock(&server->lock);
1086 @@ -112,16 +115,25 @@ int tcpconnect(struct server *server, int timeout, char *text) {
1087 if (source) freeaddrinfo(source);
1090 - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
1091 + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
1096 pthread_mutex_lock(&server->lock);
1098 - debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name);
1099 - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres)) < 0)
1100 + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
1101 + hp = (struct hostportres *)entry->data;
1102 + debug(DBG_INFO, "tcpconnect: trying to open TCP connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
1103 + if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) >= 0) {
1104 + debug(DBG_WARN, "tcpconnect: TCP connection to server %s (%s port %s) up", hp->host, hp->port);
1108 + if (server->sock < 0) {
1109 + debug(DBG_ERR, "tcpconnect: TCP connection to server %s failed", server->conf->name);
1113 if (server->conf->keepalive)
1114 enable_keepalive(server->sock);
1116 @@ -339,7 +351,7 @@ void *tcpservernew(void *arg) {
1118 debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
1120 - conf = find_clconf(handle, (struct sockaddr *)&from, NULL);
1121 + conf = find_clconf(handle, (struct sockaddr *)&from, NULL, NULL);
1123 client = addclient(conf, 1);
1125 diff --git a/tests/t_verify_cert.c b/tests/t_verify_cert.c
1126 index ca0d47e..b52a990 100644
1127 --- a/tests/t_verify_cert.c
1128 +++ b/tests/t_verify_cert.c
1129 @@ -234,7 +234,7 @@ vY/uPjA=\n\
1131 list_push(conf.hostports, &hp);
1133 - ok(1, verifyconfcert(certsimple, &conf), "check disabled");
1134 + ok(1, verifyconfcert(certsimple, &conf, &hp), "check disabled");
1136 while(list_shift(conf.hostports));
1138 @@ -249,7 +249,7 @@ vY/uPjA=\n\
1140 list_push(conf.hostports, &hp);
1142 - ok(1,verifyconfcert(certsimple, &conf),"cidr prefix");
1143 + ok(1,verifyconfcert(certsimple, &conf, &hp),"cidr prefix");
1145 while(list_shift(conf.hostports));
1147 @@ -264,11 +264,11 @@ vY/uPjA=\n\
1149 list_push(conf.hostports, &hp);
1151 - ok(1,verifyconfcert(certsimple, &conf), "simple cert cn");
1152 - ok(0,verifyconfcert(certsimpleother, &conf), "negative simple cert cn");
1153 + ok(1,verifyconfcert(certsimple, &conf, &hp), "simple cert cn");
1154 + ok(0,verifyconfcert(certsimpleother, &conf, &hp), "negative simple cert cn");
1156 /* as per RFC 6125 6.4.4: CN MUST NOT be matched if SAN is present */
1157 - ok(0,verifyconfcert(certsandns, &conf), "simple cert cn vs san dns, RFC6125");
1158 + ok(0,verifyconfcert(certsandns, &conf, &hp), "simple cert cn vs san dns, RFC6125");
1160 while(list_shift(conf.hostports));
1162 @@ -284,11 +284,11 @@ vY/uPjA=\n\
1164 list_push(conf.hostports, &hp);
1166 - ok(1,verifyconfcert(certsanip, &conf),"san ip");
1167 - ok(0,verifyconfcert(certsanipother, &conf),"wrong san ip");
1168 - ok(0,verifyconfcert(certsimple, &conf), "negative san ip");
1169 - ok(1,verifyconfcert(certsanipindns, &conf),"san ip in dns");
1170 - ok(1,verifyconfcert(certcomplex,&conf),"san ip in complex cert");
1171 + ok(1,verifyconfcert(certsanip, &conf, &hp),"san ip");
1172 + ok(0,verifyconfcert(certsanipother, &conf, &hp),"wrong san ip");
1173 + ok(0,verifyconfcert(certsimple, &conf, &hp), "negative san ip");
1174 + ok(1,verifyconfcert(certsanipindns, &conf, &hp),"san ip in dns");
1175 + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san ip in complex cert");
1177 freeaddrinfo(hp.addrinfo);
1178 while(list_shift(conf.hostports));
1179 @@ -306,11 +306,11 @@ vY/uPjA=\n\
1181 list_push(conf.hostports, &hp);
1183 - ok(1,verifyconfcert(certsanipv6, &conf),"san ipv6");
1184 - ok(0,verifyconfcert(certsanipother, &conf),"wrong san ipv6");
1185 - ok(0,verifyconfcert(certsimple, &conf),"negative san ipv6");
1186 - ok(1,verifyconfcert(certsanipv6indns, &conf),"san ipv6 in dns");
1187 - ok(1,verifyconfcert(certcomplex,&conf),"san ipv6 in complex cert");
1188 + ok(1,verifyconfcert(certsanipv6, &conf, &hp),"san ipv6");
1189 + ok(0,verifyconfcert(certsanipother, &conf, &hp),"wrong san ipv6");
1190 + ok(0,verifyconfcert(certsimple, &conf, &hp),"negative san ipv6");
1191 + ok(1,verifyconfcert(certsanipv6indns, &conf, &hp),"san ipv6 in dns");
1192 + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san ipv6 in complex cert");
1194 freeaddrinfo(hp.addrinfo);
1195 while(list_shift(conf.hostports));
1196 @@ -326,10 +326,10 @@ vY/uPjA=\n\
1198 list_push(conf.hostports, &hp);
1200 - ok(1,verifyconfcert(certsandns, &conf),"san dns");
1201 - ok(0,verifyconfcert(certsandnsother, &conf),"negative san dns");
1202 - ok(1,verifyconfcert(certcomplex,&conf),"san dns in complex cert");
1203 - ok(0,verifyconfcert(certsimple, &conf),"missing san dns");
1204 + ok(1,verifyconfcert(certsandns, &conf, &hp),"san dns");
1205 + ok(0,verifyconfcert(certsandnsother, &conf, &hp),"negative san dns");
1206 + ok(1,verifyconfcert(certcomplex,&conf, &hp),"san dns in complex cert");
1207 + ok(0,verifyconfcert(certsimple, &conf, &hp),"missing san dns");
1209 while(list_shift(conf.hostports));
1211 @@ -347,8 +347,8 @@ vY/uPjA=\n\
1212 hp2.prefixlen = 255;
1213 list_push(conf.hostports, &hp2);
1215 - ok(1,verifyconfcert(certsimple, &conf),"multi hostport cn");
1216 - ok(0,verifyconfcert(certsimpleother, &conf),"negative multi hostport cn");
1217 + ok(1,verifyconfcert(certsimple, &conf, NULL),"multi hostport cn");
1218 + ok(0,verifyconfcert(certsimpleother, &conf, NULL),"negative multi hostport cn");
1220 while(list_shift(conf.hostports));
1222 @@ -366,9 +366,14 @@ vY/uPjA=\n\
1223 hp2.prefixlen = 255;
1224 list_push(conf.hostports, &hp2);
1226 - ok(1,verifyconfcert(certsandns, &conf),"multi hostport san dns");
1227 - ok(0,verifyconfcert(certsandnsother, &conf),"negative multi hostport san dns");
1228 - ok(1,verifyconfcert(certcomplex,&conf),"multi hostport san dns in complex cert");
1229 + ok(1,verifyconfcert(certsandns, &conf, NULL),"multi hostport san dns");
1230 + ok(0,verifyconfcert(certsandnsother, &conf, NULL),"negative multi hostport san dns");
1231 + ok(1,verifyconfcert(certcomplex,&conf, NULL),"multi hostport san dns in complex cert");
1233 + ok(0,verifyconfcert(certsandns, &conf, &hp1),"multi hostport explicit wrong cert");
1234 + ok(1,verifyconfcert(certsandns, &conf, &hp2),"multi hostport explicit matching cert");
1235 + ok(0,verifyconfcert(certcomplex, &conf, &hp1),"multi hostport explicit wrong complex cert");
1236 + ok(1,verifyconfcert(certcomplex, &conf, &hp2),"multi hostport explicit matching complex cert");
1238 while(list_shift(conf.hostports));
1240 @@ -380,9 +385,9 @@ vY/uPjA=\n\
1242 ok(1,addmatchcertattr(&conf, "CN:/t..t/"),"explicit cn regex config");
1244 - ok(1,verifyconfcert(certsimple, &conf),"explicit cn regex");
1245 - ok(0,verifyconfcert(certsimpleother, &conf),"negative explicit cn regex");
1246 - ok(1,verifyconfcert(certsandns, &conf), "explicit cn regex with SAN DNS");
1247 + ok(1,verifyconfcert(certsimple, &conf, NULL),"explicit cn regex");
1248 + ok(0,verifyconfcert(certsimpleother, &conf, NULL),"negative explicit cn regex");
1249 + ok(1,verifyconfcert(certsandns, &conf, NULL), "explicit cn regex with SAN DNS");
1251 freematchcertattr(&conf);
1253 @@ -394,10 +399,10 @@ vY/uPjA=\n\
1255 ok(1,addmatchcertattr(&conf, "SubjectAltName:IP:192.0.2.1"),"explicit san ip config");
1257 - ok(1,verifyconfcert(certsanip, &conf),"explicit san ip");
1258 - ok(0,verifyconfcert(certsanipother, &conf),"wrong explicit san ip");
1259 - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san ip");
1260 - ok(1,verifyconfcert(certcomplex,&conf),"explicit san ip in complex cert");
1261 + ok(1,verifyconfcert(certsanip, &conf, NULL),"explicit san ip");
1262 + ok(0,verifyconfcert(certsanipother, &conf, NULL),"wrong explicit san ip");
1263 + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san ip");
1264 + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san ip in complex cert");
1266 freematchcertattr(&conf);
1268 @@ -409,10 +414,10 @@ vY/uPjA=\n\
1270 ok(1,addmatchcertattr(&conf, "SubjectAltName:IP:2001:db8::1"),"explicit san ipv6 config");
1272 - ok(1,verifyconfcert(certsanipv6, &conf),"explicit san ipv6");
1273 - ok(0,verifyconfcert(certsanipother, &conf),"wrong explicit san ipv6");
1274 - ok(0,verifyconfcert(certsimple, &conf),"missing explicitsan ipv6");
1275 - ok(1,verifyconfcert(certcomplex,&conf),"explicit san ipv6 in complex cert");
1276 + ok(1,verifyconfcert(certsanipv6, &conf, NULL),"explicit san ipv6");
1277 + ok(0,verifyconfcert(certsanipother, &conf, NULL),"wrong explicit san ipv6");
1278 + ok(0,verifyconfcert(certsimple, &conf, NULL),"missing explicitsan ipv6");
1279 + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san ipv6 in complex cert");
1281 freematchcertattr(&conf);
1283 @@ -424,10 +429,10 @@ vY/uPjA=\n\
1285 ok(1,addmatchcertattr(&conf, "SubjectAltName:DNS:/t..t\\.local/"),"explicit san dns regex config");
1287 - ok(1,verifyconfcert(certsandns, &conf),"explicit san dns");
1288 - ok(0,verifyconfcert(certsandnsother, &conf),"negative explicit san dns");
1289 - ok(0,verifyconfcert(certsimple,&conf),"missing explicit san dns");
1290 - ok(1,verifyconfcert(certcomplex,&conf),"explicit san dns in complex cert");
1291 + ok(1,verifyconfcert(certsandns, &conf, NULL),"explicit san dns");
1292 + ok(0,verifyconfcert(certsandnsother, &conf, NULL),"negative explicit san dns");
1293 + ok(0,verifyconfcert(certsimple,&conf, NULL),"missing explicit san dns");
1294 + ok(1,verifyconfcert(certcomplex,&conf, NULL),"explicit san dns in complex cert");
1296 freematchcertattr(&conf);
1298 @@ -439,9 +444,9 @@ vY/uPjA=\n\
1300 ok(1,addmatchcertattr(&conf, "SubjectAltName:URI:/https:\\/\\/test.local\\/profile#me/"),"explicit cn regex config");
1302 - ok(1,verifyconfcert(certsanuri, &conf),"explicit san uri regex");
1303 - ok(0,verifyconfcert(certsanuriother, &conf),"negative explicit san uri");
1304 - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san uri");
1305 + ok(1,verifyconfcert(certsanuri, &conf, NULL),"explicit san uri regex");
1306 + ok(0,verifyconfcert(certsanuriother, &conf, NULL),"negative explicit san uri");
1307 + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san uri");
1309 freematchcertattr(&conf);
1311 @@ -453,9 +458,9 @@ vY/uPjA=\n\
1313 ok(1,addmatchcertattr(&conf, "SubjectAltName:rID:1.2.3.4"),"explicit san rid config");
1315 - ok(1,verifyconfcert(certsanrid, &conf),"explicit san rid");
1316 - ok(0,verifyconfcert(certsanridother, &conf),"negative explicit san rid");
1317 - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san rid");
1318 + ok(1,verifyconfcert(certsanrid, &conf, NULL),"explicit san rid");
1319 + ok(0,verifyconfcert(certsanridother, &conf, NULL),"negative explicit san rid");
1320 + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san rid");
1322 freematchcertattr(&conf);
1324 @@ -467,9 +472,9 @@ vY/uPjA=\n\
1326 ok(1,addmatchcertattr(&conf, "SubjectAltName:otherName:1.3.6.1.5.5.7.8.8:/test.local/"),"explicit san otherName config");
1328 - ok(1,verifyconfcert(certsanothername, &conf),"explicit san otherName");
1329 - ok(0,verifyconfcert(certsanothernameother, &conf),"negative explicit san otherName");
1330 - ok(0,verifyconfcert(certsimple, &conf), "missing explicit san otherName");
1331 + ok(1,verifyconfcert(certsanothername, &conf, NULL),"explicit san otherName");
1332 + ok(0,verifyconfcert(certsanothernameother, &conf, NULL),"negative explicit san otherName");
1333 + ok(0,verifyconfcert(certsimple, &conf, NULL), "missing explicit san otherName");
1335 freematchcertattr(&conf);
1337 @@ -480,7 +485,7 @@ vY/uPjA=\n\
1338 conf.certnamecheck = 0;
1340 ok(1,addmatchcertattr(&conf, "CN:/t..t"),"test regex config syntax");
1341 - ok(1,verifyconfcert(certsimple, &conf),"test regex config syntax execution");
1342 + ok(1,verifyconfcert(certsimple, &conf, NULL),"test regex config syntax execution");
1344 freematchcertattr(&conf);
1346 @@ -518,10 +523,10 @@ vY/uPjA=\n\
1348 ok(1,addmatchcertattr(&conf, "CN:/t..t"),"combined config");
1350 - ok(1,verifyconfcert(certsandns, &conf),"combined san dns");
1351 - ok(0,verifyconfcert(certsandnsother, &conf),"negative combined san dns");
1352 - ok(1,verifyconfcert(certcomplex,&conf),"combined san dns in complex cert");
1353 - ok(0,verifyconfcert(certsimple, &conf),"combined missing san dns");
1354 + ok(1,verifyconfcert(certsandns, &conf, &hp),"combined san dns");
1355 + ok(0,verifyconfcert(certsandnsother, &conf, &hp),"negative combined san dns");
1356 + ok(1,verifyconfcert(certcomplex,&conf, &hp),"combined san dns in complex cert");
1357 + ok(0,verifyconfcert(certsimple, &conf, &hp),"combined missing san dns");
1359 while(list_shift(conf.hostports));
1360 freematchcertattr(&conf);
1361 @@ -540,12 +545,12 @@ vY/uPjA=\n\
1362 ok(1,addmatchcertattr(&conf, "SubjectAltName:DNS:/test\\.local/"),"multiple check 1");
1363 ok(1,addmatchcertattr(&conf, "SubjectAltName:rID:1.2.3.4"),"multiple check 2");
1365 - ok(0,verifyconfcert(certsandns, &conf),"multiple missing rID");
1366 - ok(0,verifyconfcert(certsanrid, &conf), "multiple missing DNS");
1367 - ok(1,verifyconfcert(certmulti, &conf),"multiple SANs");
1368 - ok(0,verifyconfcert(certmultiother, &conf),"multiple negative match");
1369 - ok(0,verifyconfcert(certcomplex, &conf),"multiple missing rID in complex cert");
1370 - ok(0,verifyconfcert(certsimple, &conf),"multiple missing everything");
1371 + ok(0,verifyconfcert(certsandns, &conf, &hp),"multiple missing rID");
1372 + ok(0,verifyconfcert(certsanrid, &conf, &hp), "multiple missing DNS");
1373 + ok(1,verifyconfcert(certmulti, &conf, &hp),"multiple SANs");
1374 + ok(0,verifyconfcert(certmultiother, &conf, &hp),"multiple negative match");
1375 + ok(0,verifyconfcert(certcomplex, &conf, &hp),"multiple missing rID in complex cert");
1376 + ok(0,verifyconfcert(certsimple, &conf, &hp),"multiple missing everything");
1378 while(list_shift(conf.hostports));
1379 freematchcertattr(&conf);
1380 diff --git a/tls.c b/tls.c
1381 index 87bbe2c..049f3a9 100644
1386 #include "radsecproxy.h"
1387 #include "hostport.h"
1395 static void setprotoopts(struct commonprotoopts *opts);
1396 static char **getlistenerargs();
1397 void *tlslistener(void *arg);
1398 @@ -82,6 +82,17 @@ void tlssetsrcres() {
1399 AF_UNSPEC, NULL, protodefs.socktype);
1402 +static void cleanup_connection(struct server *server) {
1404 + SSL_shutdown(server->ssl);
1405 + if (server->sock >= 0)
1406 + close(server->sock);
1407 + server->sock = -1;
1409 + SSL_free(server->ssl);
1410 + server->ssl = NULL;
1413 int tlsconnect(struct server *server, int timeout, char *text) {
1414 struct timeval now, start;
1416 @@ -92,6 +103,8 @@ int tlsconnect(struct server *server, int timeout, char *text) {
1418 struct addrinfo *source = NULL;
1420 + struct list_node *entry;
1421 + struct hostportres *hp;
1423 debug(DBG_DBG, "tlsconnect: called from %s", text);
1424 pthread_mutex_lock(&server->lock);
1425 @@ -108,15 +121,7 @@ int tlsconnect(struct server *server, int timeout, char *text) {
1426 gettimeofday(&start, NULL);
1429 - /* ensure previous connection is properly closed */
1431 - SSL_shutdown(server->ssl);
1432 - if (server->sock >= 0)
1433 - close(server->sock);
1435 - SSL_free(server->ssl);
1436 - server->ssl = NULL;
1438 + cleanup_connection(server);
1439 wait = connect_wait(start, server->connecttime, firsttry);
1440 gettimeofday(&now, NULL);
1441 if (timeout && (now.tv_sec - start.tv_sec) + wait > timeout) {
1442 @@ -124,7 +129,7 @@ int tlsconnect(struct server *server, int timeout, char *text) {
1443 if (source) freeaddrinfo(source);
1446 - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
1447 + if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
1451 @@ -135,46 +140,76 @@ int tlsconnect(struct server *server, int timeout, char *text) {
1455 - debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name);
1456 - if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres)) < 0)
1458 - if (server->conf->keepalive)
1459 - enable_keepalive(server->sock);
1460 + for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
1461 + hp = (struct hostportres *)entry->data;
1462 + debug(DBG_INFO, "tlsconnect: trying to open TLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
1463 + if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) < 0 ) {
1464 + debug(DBG_ERR, "tlsconnect: TLS connection to %s (%s port %s) failed: TCP connect failed", server->conf->name, hp->host, hp->port);
1468 + if (server->conf->keepalive)
1469 + enable_keepalive(server->sock);
1471 + pthread_mutex_lock(&server->conf->tlsconf->lock);
1472 + if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))) {
1473 + pthread_mutex_unlock(&server->conf->tlsconf->lock);
1474 + debug(DBG_ERR, "tlsconnect: failed to get TLS context for server %s", server->conf->name);
1478 - pthread_mutex_lock(&server->conf->tlsconf->lock);
1479 - if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
1480 + server->ssl = SSL_new(ctx);
1481 pthread_mutex_unlock(&server->conf->tlsconf->lock);
1484 + if (!server->ssl) {
1485 + debug(DBG_ERR, "tlsconnect: failed to create SSL conneciton for server %s", server->conf->name);
1489 - server->ssl = SSL_new(ctx);
1490 - pthread_mutex_unlock(&server->conf->tlsconf->lock);
1493 + if (server->conf->sni) {
1494 + struct in6_addr tmp;
1495 + char *servername = server->conf->sniservername ? server->conf->sniservername :
1496 + (inet_pton(AF_INET, hp->host, &tmp) || inet_pton(AF_INET6, hp->host, &tmp)) ? NULL : hp->host;
1497 + if (servername && !tlssetsni(server->ssl, servername)) {
1498 + debug(DBG_ERR, "tlsconnect: set SNI %s failed", servername);
1503 + SSL_set_fd(server->ssl, server->sock);
1504 + if (sslconnecttimeout(server->ssl, 5) <= 0) {
1505 + while ((error = ERR_get_error()))
1506 + debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
1507 + debug(DBG_ERR, "tlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port);
1511 - SSL_set_fd(server->ssl, server->sock);
1512 - if (sslconnecttimeout(server->ssl, 5) <= 0) {
1513 - while ((error = ERR_get_error()))
1514 - debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
1515 - debug(DBG_ERR, "tlsconnect: SSL connect to %s failed", server->conf->name);
1518 + cert = verifytlscert(server->ssl);
1520 + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
1524 - cert = verifytlscert(server->ssl);
1527 - if (verifyconfcert(cert, server->conf)) {
1528 - subj = getcertsubject(cert);
1530 - debug(DBG_WARN, "tlsconnect: TLS connection to %s, subject %s up", server->conf->name, subj);
1532 + if (verifyconfcert(cert, server->conf, hp)) {
1533 + subj = getcertsubject(cert);
1535 + debug(DBG_WARN, "tlsconnect: TLS connection to %s (%s port %s), subject %s, %s with cipher %s up",
1536 + server->conf->name, hp->host, hp->port, subj,
1537 + SSL_get_version(server->ssl), SSL_CIPHER_get_name(SSL_get_current_cipher(server->ssl)));
1543 + debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
1549 + /* ensure previous connection is properly closed */
1550 + cleanup_connection(server);
1553 + if (server->ssl) break;
1555 - debug(DBG_WARN, "tlsconnect: TLS connection to %s up", server->conf->name);
1557 origflags = fcntl(server->sock, F_GETFL, 0);
1558 if (origflags == -1) {
1559 @@ -251,6 +286,7 @@ int sslreadtimeout(SSL *ssl, unsigned char *buf, int num, int timeout, pthread_m
1561 case SSL_ERROR_ZERO_RETURN:
1562 debug(DBG_DBG, "sslreadtimeout: got ssl shutdown");
1565 while ((error = ERR_get_error()))
1566 debug(DBG_ERR, "sslreadtimeout: SSL: %s", ERR_error_string(error, NULL));
1567 @@ -505,6 +541,7 @@ void *tlsservernew(void *arg) {
1568 struct client *client;
1569 struct tls *accepted_tls = NULL;
1570 char tmp[INET6_ADDRSTRLEN], *subj;
1571 + struct hostportres *hp;
1575 @@ -514,7 +551,7 @@ void *tlsservernew(void *arg) {
1577 debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
1579 - conf = find_clconf(handle, (struct sockaddr *)&from, &cur);
1580 + conf = find_clconf(handle, (struct sockaddr *)&from, &cur, &hp);
1582 pthread_mutex_lock(&conf->tlsconf->lock);
1583 ctx = tlsgetctx(handle, conf->tlsconf);
1584 @@ -549,11 +586,12 @@ void *tlsservernew(void *arg) {
1588 - if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf)) {
1589 + if (accepted_tls == conf->tlsconf && verifyconfcert(cert, conf, NULL)) {
1590 subj = getcertsubject(cert);
1592 - debug(DBG_WARN, "tlsservernew: TLS connection from %s, client %s, subject %s up",
1593 - addr2string((struct sockaddr *)&from,tmp, sizeof(tmp)), conf->name, subj);
1594 + debug(DBG_WARN, "tlsservernew: TLS connection from %s, client %s, subject %s, %s with cipher %s up",
1595 + addr2string((struct sockaddr *)&from,tmp, sizeof(tmp)), conf->name, subj,
1596 + SSL_get_version(ssl), SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
1600 @@ -569,9 +607,10 @@ void *tlsservernew(void *arg) {
1601 debug(DBG_WARN, "tlsservernew: failed to create new client instance");
1604 - conf = find_clconf(handle, (struct sockaddr *)&from, &cur);
1605 + conf = find_clconf(handle, (struct sockaddr *)&from, &cur, &hp);
1607 - debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client");
1608 + debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client for %s",
1609 + addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
1613 diff --git a/tlscommon.c b/tlscommon.c
1614 index 0bd7da4..2dc0f48 100644
1617 @@ -492,12 +492,26 @@ static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
1620 if (conf->dhparam) {
1621 +#if OPENSSL_VERSION_NUMBER >= 0x30000000
1622 + if (!SSL_CTX_set0_tmp_dh_pkey(ctx, conf->dhparam)) {
1624 if (!SSL_CTX_set_tmp_dh(ctx, conf->dhparam)) {
1626 while ((error = ERR_get_error()))
1627 debug(DBG_WARN, "tlscreatectx: SSL: %s", ERR_error_string(error, NULL));
1628 debug(DBG_WARN, "tlscreatectx: Failed to set dh params. Can continue, but some ciphers might not be available.");
1631 +#if OPENSSL_VERSION_NUMBER >= 0x10100000
1633 + if (!SSL_CTX_set_dh_auto(ctx, 1)) {
1634 + while ((error = ERR_get_error()))
1635 + debug(DBG_WARN, "tlscreatectx: SSL: %s", ERR_error_string(error, NULL));
1636 + debug(DBG_WARN, "tlscreatectx: Failed to set automatic dh params. Can continue, but some ciphers might not be available.");
1641 debug(DBG_DBG, "tlscreatectx: created TLS context %s", conf->name);
1644 @@ -506,7 +520,7 @@ struct tls *tlsgettls(char *alt1, char *alt2) {
1647 t = hash_read(tlsconfs, alt1, strlen(alt1));
1650 t = hash_read(tlsconfs, alt2, strlen(alt2));
1653 @@ -711,64 +725,67 @@ static int matchsubjaltname(X509 *cert, struct certattrmatch* match) {
1657 - debug(DBG_WARN, "matchsubjaltname: no matching Subject Alt Name found! (%s)", fail);
1658 + debug(DBG_DBG, "matchsubjaltname: no matching Subject Alt Name found! (%s)", fail);
1661 GENERAL_NAMES_free(alt);
1665 -int certnamecheck(X509 *cert, struct list *hostports) {
1666 - struct list_node *entry;
1667 - struct hostportres *hp;
1668 +int certnamecheck(X509 *cert, struct hostportres *hp) {
1670 struct certattrmatch match;
1672 memset(&match, 0, sizeof(struct certattrmatch));
1674 - for (entry = list_first(hostports); entry; entry = list_next(entry)) {
1676 - hp = (struct hostportres *)entry->data;
1677 - if (hp->prefixlen != 255) {
1678 - /* we disable the check for prefixes */
1680 + if (hp->prefixlen != 255) {
1681 + /* we disable the check for prefixes */
1684 + if (inet_pton(AF_INET, hp->host, &match.ipaddr))
1685 + match.af = AF_INET;
1686 + else if (inet_pton(AF_INET6, hp->host, &match.ipaddr))
1687 + match.af = AF_INET6;
1690 + match.exact = hp->host;
1693 + match.matchfn = &certattr_matchip;
1694 + match.type = GEN_IPADD;
1695 + r = matchsubjaltname(cert, &match);
1698 + match.matchfn = &certattr_matchregex;
1699 + match.type = GEN_DNS;
1700 + r = matchsubjaltname(cert, &match);
1704 + debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", match.af ? "address" : "host", hp->host);
1707 - if (inet_pton(AF_INET, hp->host, &match.ipaddr))
1708 - match.af = AF_INET;
1709 - else if (inet_pton(AF_INET6, hp->host, &match.ipaddr))
1710 - match.af = AF_INET6;
1713 - match.exact = hp->host;
1716 - match.matchfn = &certattr_matchip;
1717 - match.type = GEN_IPADD;
1718 - r = matchsubjaltname(cert, &match);
1721 - match.matchfn = &certattr_matchregex;
1722 - match.type = GEN_DNS;
1723 - r = matchsubjaltname(cert, &match);
1727 - debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", match.af ? "address" : "host", hp->host);
1730 - debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", match.af ? "address" : "host", hp->host);
1732 - if (certattr_matchcn(cert, &match)) {
1733 - debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host);
1736 - debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host);
1737 + debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", match.af ? "address" : "host", hp->host);
1738 + } else { /* as per RFC 6125 6.4.4: CN MUST NOT be matched if SAN is present */
1739 + if (certattr_matchcn(cert, &match)) {
1740 + debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host);
1743 + debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host);
1748 -int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
1749 +int certnamecheckany(X509 *cert, struct list *hostports) {
1750 + struct list_node *entry;
1751 + for (entry = list_first(hostports); entry; entry = list_next(entry)) {
1752 + if (certnamecheck(cert, (struct hostportres *)entry->data)) return 1;
1757 +int verifyconfcert(X509 *cert, struct clsrvconf *conf, struct hostportres *hpconnected) {
1760 struct list_node *entry;
1761 @@ -777,9 +794,16 @@ int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
1762 debug(DBG_DBG, "verifyconfcert: verify certificate for host %s, subject %s", conf->name, subject);
1763 if (conf->certnamecheck) {
1764 debug(DBG_DBG, "verifyconfcert: verify hostname");
1765 - if (!certnamecheck(cert, conf->hostports)) {
1766 - debug(DBG_DBG, "verifyconfcert: certificate name check failed for host %s", conf->name);
1768 + if (hpconnected) {
1769 + if (!certnamecheck(cert, hpconnected)) {
1770 + debug(DBG_WARN, "verifyconfcert: certificate name check failed for host %s (%s)", conf->name, hpconnected->host);
1774 + if (!certnamecheckany(cert, conf->hostports)) {
1775 + debug(DBG_DBG, "verifyconfcert: no matching CN or SAN found for host %s", conf->name);
1781 @@ -913,11 +937,27 @@ int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *v
1785 + if (tlsversion || dtlsversion) {
1786 debug(DBG_ERR, "error in block %s, setting tls/dtls version requires openssl 1.1.0 or later", val);
1792 +#if OPENSSL_VERSION_NUMBER >= 0x30000000
1793 + BIO *bio = BIO_new_file(dhfile, "r");
1795 + conf->dhparam = EVP_PKEY_new();
1796 + if (!PEM_read_bio_Parameters(bio, &conf->dhparam)) {
1798 + while ((error = ERR_get_error()))
1799 + debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
1800 + debug(DBG_ERR, "error in block %s: Failed to load DhFile %s.", val, dhfile);
1806 FILE *dhfp = fopen(dhfile, "r");
1808 conf->dhparam = PEM_read_DHparams(dhfp, NULL, NULL, NULL);
1809 @@ -934,6 +974,7 @@ int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *v
1816 conf->name = stringcopy(val, 0);
1817 @@ -964,7 +1005,11 @@ errexit:
1821 +#if OPENSSL_VERSION_NUMBER >= 0x30000000
1822 + EVP_PKEY_free(conf->dhparam);
1824 DH_free(conf->dhparam);
1829 @@ -1091,6 +1136,10 @@ void freematchcertattr(struct clsrvconf *conf) {
1833 +int tlssetsni(SSL *ssl, char *sni) {
1834 + return SSL_set_tlsext_host_name(ssl, sni);
1837 int sslaccepttimeout (SSL *ssl, int timeout) {
1838 int socket, origflags, ndesc, r = -1, sockerr = 0;
1839 socklen_t errlen = sizeof(sockerr);
1840 diff --git a/tlscommon.h b/tlscommon.h
1841 index 6be9079..1006626 100644
1845 /* See LICENSE for licensing information. */
1847 #include <openssl/ssl.h>
1848 +#include "hostport.h"
1850 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1851 #define ASN1_STRING_get0_data(o) ((o)->data)
1852 @@ -25,7 +26,11 @@ struct tls {
1856 +#if OPENSSL_VERSION_NUMBER >= 0x30000000
1857 + EVP_PKEY* dhparam;
1862 uint32_t dtlsexpiry;
1863 X509_VERIFY_PARAM *vpm;
1864 @@ -40,12 +45,13 @@ void sslinit();
1865 struct tls *tlsgettls(char *alt1, char *alt2);
1866 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t);
1867 X509 *verifytlscert(SSL *ssl);
1868 -int verifyconfcert(X509 *cert, struct clsrvconf *conf);
1869 +int verifyconfcert(X509 *cert, struct clsrvconf *conf, struct hostportres *);
1870 char *getcertsubject(X509 *cert);
1871 int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val);
1872 int addmatchcertattr(struct clsrvconf *conf, const char *match);
1873 void freematchcertattr(struct clsrvconf *conf);
1874 void tlsreloadcrls();
1875 +int tlssetsni(SSL *ssl, char *sni);
1876 int sslconnecttimeout(SSL *ssl, int timeout);
1877 int sslaccepttimeout (SSL *ssl, int timeout);
1879 diff --git a/tlv11.c b/tlv11.c
1880 index d570b39..9eaf6d9 100644
1886 #include <arpa/inet.h>
1889 struct tlv *maketlv(uint8_t t, uint8_t l, void *v) {
1891 @@ -97,6 +98,8 @@ void rmtlv(struct list *tlvs, uint8_t t) {
1894 uint8_t *tlv2str(struct tlv *tlv) {
1897 uint8_t *s = malloc(tlv->l + 1);
1899 memcpy(s, tlv->v, tlv->l);
1900 @@ -117,6 +120,28 @@ struct tlv *resizetlv(struct tlv *tlv, uint8_t newlen) {
1904 +uint32_t tlv2longint(struct tlv *tlv) {
1905 + if (!tlv) return 0;
1906 + if (tlv->l != sizeof(uint32_t)) return 0;
1907 + return ntohl(*(uint32_t *)tlv->v);
1910 +char* tlv2ipv4addr(struct tlv *tlv) {
1913 + if (!tlv) return NULL;
1914 + if (tlv->l != sizeof(in_addr_t)) return NULL;
1916 + result = malloc(INET_ADDRSTRLEN);
1917 + if (!result) return NULL;
1919 + if (!inet_ntop(AF_INET, tlv->v, result, INET_ADDRSTRLEN)) {
1926 /* Local Variables: */
1927 /* c-file-style: "stroustrup" */
1929 diff --git a/tlv11.h b/tlv11.h
1930 index 84db3d7..c565d13 100644
1933 @@ -17,6 +17,8 @@ void freetlvlist(struct list *);
1934 void rmtlv(struct list *, uint8_t);
1935 uint8_t *tlv2str(struct tlv *tlv);
1936 struct tlv *resizetlv(struct tlv *, uint8_t);
1937 +uint32_t tlv2longint(struct tlv *tlv);
1938 +char* tlv2ipv4addr(struct tlv *tlv);
1940 /* Local Variables: */
1941 /* c-file-style: "stroustrup" */
1942 diff --git a/tools/naptr-eduroam.sh b/tools/naptr-eduroam.sh
1943 index 5402d18..2f90601 100755
1944 --- a/tools/naptr-eduroam.sh
1945 +++ b/tools/naptr-eduroam.sh
1946 @@ -14,7 +14,6 @@ usage() {
1948 test -n "${1}" || usage
1951 DIGCMD=$(command -v dig)
1952 HOSTCMD=$(command -v host)
1953 PRINTCMD=$(command -v printf)
1954 @@ -38,7 +37,7 @@ dig_it_srv() {
1958 - ${DIGCMD} +short naptr ${REALM} | grep x-eduroam:radius.tls | sort -n -k1 |
1959 + ${DIGCMD} +short naptr "${REALM}" | grep x-eduroam:radius.tls | sort -n -k1 |
1961 set $line ; TYPE=$3 ; HOST=$(validate_host $6)
1962 if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then
1963 @@ -59,7 +58,7 @@ host_it_srv() {
1967 - ${HOSTCMD} -t naptr ${REALM} | grep x-eduroam:radius.tls | sort -n -k5 |
1968 + ${HOSTCMD} -t naptr "${REALM}" | grep x-eduroam:radius.tls | sort -n -k5 |
1970 set $line ; TYPE=$7 ; HOST=$(validate_host ${10})
1971 if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then
1972 @@ -69,6 +68,12 @@ host_it_naptr() {
1976 +REALM=$(validate_host ${1})
1977 +if [ -z "${REALM}" ]; then
1978 + echo "Error: realm \"${1}\" failed validation"
1982 if [ -x "${DIGCMD}" ]; then
1983 SERVERS=$(dig_it_naptr)
1984 elif [ -x "${HOSTCMD}" ]; then
1985 @@ -79,7 +84,7 @@ else
1988 if [ -n "${SERVERS}" ]; then
1989 - $PRINTCMD "server dynamic_radsec.${REALM} {\n${SERVERS}\n\ttype TLS\n}\n"
1990 + $PRINTCMD "server dynamic_radsec.${REALM} {\n${SERVERS}\n}\n"
1994 diff --git a/tools/radsec-dynsrv.sh b/tools/radsec-dynsrv.sh
1995 index 68bb5ba..d8318ed 100755
1996 --- a/tools/radsec-dynsrv.sh
1997 +++ b/tools/radsec-dynsrv.sh
1998 @@ -14,7 +14,6 @@ usage() {
2000 test -n "${1}" || usage
2003 DIGCMD=$(command -v digaaa)
2004 HOSTCMD=$(command -v host)
2005 PRINTCMD=$(command -v printf)
2006 @@ -28,7 +27,7 @@ validate_port() {
2010 - ${DIGCMD} +short srv _radsec._tcp.${REALM} | sort -n -k1 |
2011 + ${DIGCMD} +short srv "_radsec._tcp.${REALM}" | sort -n -k1 |
2012 while read line ; do
2013 set $line ; PORT=$(validate_port $3) ; HOST=$(validate_host $4)
2014 if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then
2015 @@ -38,7 +37,7 @@ dig_it() {
2019 - ${HOSTCMD} -t srv _radsec._tcp.${REALM} | sort -n -k5 |
2020 + ${HOSTCMD} -t srv "_radsec._tcp.${REALM}" | sort -n -k5 |
2021 while read line ; do
2022 set $line ; PORT=$(validate_port $7) ; HOST=$(validate_host $8)
2023 if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then
2024 @@ -47,6 +46,12 @@ host_it() {
2028 +REALM=$(validate_host ${1})
2029 +if test -z "${REALM}" ; then
2030 + echo "Error: realm \"${1}\" failed validation"
2034 if test -x "${DIGCMD}" ; then
2036 elif test -x "${HOSTCMD}" ; then
2037 @@ -57,7 +62,7 @@ else
2040 if test -n "${SERVERS}" ; then
2041 - $PRINTCMD "server dynamic_radsec.${REALM} {\n${SERVERS}\n\ttype TLS\n}\n"
2042 + $PRINTCMD "server dynamic_radsec.${REALM} {\n${SERVERS}\n}\n"
2046 diff --git a/udp.c b/udp.c
2047 index e3e1464..6e86fbe 100644
2050 @@ -160,7 +160,7 @@ unsigned char *radudpget(int s, struct client **client, struct server **server)
2054 - ? find_clconf(handle, (struct sockaddr *)&from, NULL)
2055 + ? find_clconf(handle, (struct sockaddr *)&from, NULL, NULL)
2056 : find_srvconf(handle, (struct sockaddr *)&from, NULL);
2058 debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));