diff --git a/ChangeLog b/ChangeLog index 71a1490..11cff1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,11 +3,16 @@ changes since 1.7.2 - Rewrite: supplement attribute (add attribute if not present) (#19) - Rewrite: modify vendor attribute - Rewrite whitelist mode + - Autodetect status-server capability of servers + - Minimalistic status-server Misc: - No longer require docbook2x tools, but include plain manpages - Fail on startup if overlapping clients with different tls blocks + Compile fixes: + - Fix compile issues on bsd + Bug fixes: - Handle %00 in config correctly (#31) @@ -279,7 +284,7 @@ changes since 1.7.2 2008-10-07 1.2 listenTCP and sourceTCP options renamed to listenTLS and sourceTLS - Old options deprecated but available for backwards compatiblity + Old options deprecated but available for backwards compatibility Logging reply-message attribute from Reject messages Contribution from Arne Schwabe Rewrite blocks have new options addAttribute and modifyAttribute diff --git a/dtls.c b/dtls.c index 7c2c315..c4d9fd8 100644 --- a/dtls.c +++ b/dtls.c @@ -35,7 +35,7 @@ static void setprotoopts(struct commonprotoopts *opts); static char **getlistenerargs(); void *dtlslistener(void *arg); -int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text); +int dtlsconnect(struct server *server, int timeout, char *text); void *dtlsclientrd(void *arg); int clientradputdtls(struct server *server, unsigned char *rad); void addserverextradtls(struct clsrvconf *conf); @@ -400,12 +400,24 @@ int getConnectionInfo(int socket, struct sockaddr *from, socklen_t fromlen, stru if (getsockname(socket, to, &tolen)) return -1; for (ctrlhdr = CMSG_FIRSTHDR(&msghdr); ctrlhdr; ctrlhdr = CMSG_NXTHDR(&msghdr, ctrlhdr)) { +#if defined(IP_PKTINFO) if(ctrlhdr->cmsg_level == IPPROTO_IP && ctrlhdr->cmsg_type == IP_PKTINFO) { - debug(DBG_DBG, "udp packet to: %s", inet_ntop(AF_INET, &((struct in_pktinfo *)CMSG_DATA(ctrlhdr))->ipi_addr, tmp, sizeof(tmp))); + struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(ctrlhdr); + debug(DBG_DBG, "udp packet to: %s", inet_ntop(AF_INET, &(pktinfo->ipi_addr), tmp, sizeof(tmp))); - ((struct sockaddr_in *)to)->sin_addr = ((struct in_pktinfo *)CMSG_DATA(ctrlhdr))->ipi_addr; + ((struct sockaddr_in *)to)->sin_addr = pktinfo->ipi_addr; toaddrfound = 1; - } else if(ctrlhdr->cmsg_level == IPPROTO_IPV6 && ctrlhdr->cmsg_type == IPV6_RECVPKTINFO) { + } +#elif defined(IP_RECVDSTADDR) + if(ctrlhdr->cmsg_level == IPPROTO_IP && ctrlhdr->cmsg_type == IP_RECVDSTADDR) { + struct in_addr *addr = (struct in_addr *)CMSG_DATA(ctrlhdr); + debug(DBG_DBG, "udp packet to: %s", inet_ntop(AF_INET, addr, tmp, sizeof(tmp))); + + ((struct sockaddr_in *)to)->sin_addr = *addr; + toaddrfound = 1; + } +#endif + if(ctrlhdr->cmsg_level == IPPROTO_IPV6 && ctrlhdr->cmsg_type == IPV6_RECVPKTINFO) { info6 = (struct in6_pktinfo *)CMSG_DATA(ctrlhdr); debug(DBG_DBG, "udp packet to: %x", inet_ntop(AF_INET6, &info6->ipi6_addr, tmp, sizeof(tmp))); @@ -502,9 +514,10 @@ void *dtlslistener(void *arg) { return NULL; } -int dtlsconnect(struct server *server, struct timeval *when, int timeout, char *text) { - struct timeval socktimeout, now, start = {0,0}; +int dtlsconnect(struct server *server, int timeout, char *text) { + struct timeval socktimeout, now, start; time_t wait; + int firsttry = 1; X509 *cert; SSL_CTX *ctx = NULL; struct hostportres *hp; @@ -520,12 +533,7 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char * pthread_mutex_unlock(&server->lock); hp = (struct hostportres *)list_first(server->conf->hostports)->data; - - gettimeofday(&now, NULL); - if (when && (now.tv_sec - when->tv_sec) < 30 ) { - /* last connection was less than 30s ago. Delay next attempt */ - start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec); - } + gettimeofday(&start, NULL); for (;;) { /* ensure previous connection is properly closed */ @@ -537,30 +545,18 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char * SSL_free(server->ssl); server->ssl = NULL; - /* no sleep at startup or at first try */ - if (start.tv_sec) { - gettimeofday(&now, NULL); - wait = abs(now.tv_sec - start.tv_sec); - wait = wait > 60 ? 60 : wait; - - if (timeout && (now.tv_sec - start.tv_sec) > timeout) { - debug(DBG_DBG, "tlsconnect: timeout"); - return 0; - } + wait = connect_wait(start, server->connecttime, firsttry); + debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + sleep(wait); + firsttry = 0; - if (wait < 1) - sleep(2); - else { - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); - sleep(wait); - } - debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name); - } else { - gettimeofday(&start, NULL); + gettimeofday(&now, NULL); + if (timeout && (now.tv_sec - start.tv_sec) > timeout) { + debug(DBG_DBG, "tlsconnect: timeout"); + return 0; } - /* done sleeping */ - debug(DBG_WARN, "dtlsconnect: trying to open DTLS connection to %s port %s", hp->host, hp->port); + debug(DBG_INFO, "dtlsconnect: connecting to %s port %s", hp->host, hp->port); if ((server->sock = bindtoaddr(srcres, hp->addrinfo->ai_family, 0)) < 0) continue; @@ -605,7 +601,7 @@ int dtlsconnect(struct server *server, struct timeval *when, int timeout, char * pthread_mutex_lock(&server->lock); server->state = RSP_SERVER_STATE_CONNECTED; - gettimeofday(&server->lastconnecttry, NULL); + gettimeofday(&server->connecttime, NULL); pthread_mutex_unlock(&server->lock); pthread_mutex_lock(&server->newrq_mutex); server->conreset = 1; @@ -647,11 +643,8 @@ int clientradputdtls(struct server *server, unsigned char *rad) { void *dtlsclientrd(void *arg) { struct server *server = (struct server *)arg; unsigned char *buf; - struct timeval lastconnecttry; for (;;) { - /* yes, lastconnecttry is really necessary */ - lastconnecttry = server->lastconnecttry; buf = raddtlsget(server->ssl, 5, &server->lock); if (!buf) { if(SSL_get_shutdown(server->ssl) || server->lostrqs) { @@ -659,7 +652,7 @@ void *dtlsclientrd(void *arg) { debug (DBG_WARN, "tlscleintrd: connection to server %s lost", server->conf->name); else if (server->lostrqs) debug (DBG_WARN, "dtlsclientrd: server %s did not respond, closing connection.", server->conf->name); - dtlsconnect(server, &lastconnecttry, 0, "dtlsclientrd"); + dtlsconnect(server, 0, "dtlsclientrd"); server->lostrqs = 0; } continue; diff --git a/radsecproxy.c b/radsecproxy.c index b250120..c0f3493 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -471,7 +471,7 @@ void sendrq(struct request *rq) { if (!to) goto errexit; - start = to->conf->statusserver ? 1 : 0; + start = to->conf->statusserver == RSP_STATSRV_OFF ? 0 : 1; pthread_mutex_lock(&to->newrq_mutex); if (start && rq->msg->code == RAD_Status_Server) { if (!_internal_sendrq(to, 0, rq)) { @@ -1422,9 +1422,11 @@ void replyh(struct server *server, unsigned char *buf) { gettimeofday(&server->lastrcv, NULL); if (rqout->rq->msg->code == RAD_Status_Server) { - freerqoutdata(rqout); - debug(DBG_NOTICE, "replyh: got status server response from %s", server->conf->name); - goto errunlock; + freerqoutdata(rqout); + debug(DBG_NOTICE, "replyh: got status server response from %s", server->conf->name); + if (server->conf->statusserver == RSP_STATSRV_AUTO) + server->conf->statusserver = RSP_STATSRV_MINIMAL; + goto errunlock; } gettimeofday(&server->lastreply, NULL); @@ -1537,7 +1539,7 @@ void *clientwr(void *arg) { pthread_t clientrdth; int i, dynconffail = 0; time_t secs; - uint8_t rnd, do_resend = 0; + uint8_t rnd, do_resend = 0, statusserver_requested = 0; struct timeval now, laststatsrv; struct timespec timeout; struct request *statsrvrq; @@ -1569,14 +1571,12 @@ void *clientwr(void *arg) { memset(&timeout, 0, sizeof(struct timespec)); - if (conf->statusserver) { - gettimeofday(&server->lastrcv, NULL); - gettimeofday(&laststatsrv, NULL); - } gettimeofday(&server->lastreply, NULL); + server->lastrcv = server->lastreply; + laststatsrv = server->lastreply; if (conf->pdef->connecter) { - if (!conf->pdef->connecter(server, NULL, server->dynamiclookuparg ? 5 : 0, "clientwr")) { + if (!conf->pdef->connecter(server, server->dynamiclookuparg ? 5 : 0, "clientwr")) { server->state = RSP_SERVER_STATE_FAILING; if (server->dynamiclookuparg) { debug(DBG_WARN, "%s: connect failed, sleeping %ds", @@ -1600,7 +1600,7 @@ void *clientwr(void *arg) { /* random 0-7 seconds */ RAND_bytes(&rnd, 1); rnd /= 32; - if (conf->statusserver) { + if (conf->statusserver != RSP_STATSRV_OFF) { secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec; if (now.tv_sec - secs > STATUS_SERVER_PERIOD) secs = now.tv_sec; @@ -1664,24 +1664,33 @@ void *clientwr(void *arg) { continue; } - if (rqout->tries == (*rqout->rq->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) { - debug(DBG_DBG, "clientwr: removing expired packet from queue"); - replylog(rqout->rq->msg, server, rqout->rq); - if (conf->statusserver) { - if (*rqout->rq->buf == RAD_Status_Server) { - debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->name); - if (server->lostrqs < 255) - server->lostrqs++; - } + if (rqout->tries > 0 && now.tv_sec - server->lastrcv.tv_sec > conf->retryinterval) + statusserver_requested = 1; + if (rqout->tries == (*rqout->rq->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) { + debug(DBG_DBG, "clientwr: removing expired packet from queue"); + replylog(rqout->rq->msg, server, rqout->rq); + if (conf->statusserver == RSP_STATSRV_ON || conf->statusserver == RSP_STATSRV_MINIMAL) { + if (*rqout->rq->buf == RAD_Status_Server) { + debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->name); + if (server->lostrqs < 255) + server->lostrqs++; + } + } else { + if (conf->statusserver == RSP_STATSRV_AUTO && *rqout->rq->buf == RAD_Status_Server) { + if (server->lastreply.tv_sec >= laststatsrv.tv_sec) { + debug(DBG_DBG, "clientwr: status server autodetect faild, disabling status server for %s", conf->name); + conf->statusserver = RSP_STATSRV_OFF; + } } else { - debug(DBG_WARN, "clientwr: no server response, %s dead?", conf->name); - if (server->lostrqs < 255) - server->lostrqs++; - } - freerqoutdata(rqout); - pthread_mutex_unlock(rqout->lock); - continue; - } + debug(DBG_WARN, "clientwr: no server response, %s dead?", conf->name); + if (server->lostrqs < 255) + server->lostrqs++; + } + } + freerqoutdata(rqout); + pthread_mutex_unlock(rqout->lock); + continue; + } rqout->expiry.tv_sec = now.tv_sec + conf->retryinterval; if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec) @@ -1694,19 +1703,22 @@ void *clientwr(void *arg) { pthread_mutex_unlock(rqout->lock); } do_resend = 0; - if (conf->statusserver && server->state == RSP_SERVER_STATE_CONNECTED) { - secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec; - gettimeofday(&now, NULL); - if (now.tv_sec - secs > STATUS_SERVER_PERIOD) { - laststatsrv = now; - statsrvrq = createstatsrvrq(); - if (statsrvrq) { - statsrvrq->to = server; - debug(DBG_DBG, "clientwr: sending %s to %s", radmsgtype2string(RAD_Status_Server), conf->name); - sendrq(statsrvrq); - } - } - } + if (server->state == RSP_SERVER_STATE_CONNECTED && !(conf->statusserver == RSP_STATSRV_OFF)) { + gettimeofday(&now, NULL); + if ((conf->statusserver == RSP_STATSRV_ON && now.tv_sec - (laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec) > STATUS_SERVER_PERIOD) || + (conf->statusserver == RSP_STATSRV_MINIMAL && statusserver_requested && now.tv_sec - laststatsrv.tv_sec > STATUS_SERVER_PERIOD) || + (conf->statusserver == RSP_STATSRV_AUTO && server->lastreply.tv_sec >= laststatsrv.tv_sec)) { + + laststatsrv = now; + statsrvrq = createstatsrvrq(); + if (statsrvrq) { + statsrvrq->to = server; + debug(DBG_DBG, "clientwr: sending %s to %s", radmsgtype2string(RAD_Status_Server), conf->name); + sendrq(statsrvrq); + } + statusserver_requested = 0; + } + } } errexit: if (server->dynamiclookuparg) { @@ -1750,8 +1762,13 @@ void createlistener(uint8_t type, char *arg) { if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == -1) debugerrno(errno, DBG_WARN, "craetelistener: IPV6_RECVPKTINFO"); } else if (res->ai_family == AF_INET) { +#if defined(IP_PKTINFO) if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) == -1) debugerrno(errno, DBG_WARN, "createlistener: IP_PKTINFO"); +#elif defined(IP_RECVDSTADDR) + if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) == -1) + debugerrno(errno, DBG_WARN, "createlistener: IP_RECVDSTADDR"); +#endif } } if (bind(s, res->ai_addr, res->ai_addrlen)) { @@ -2462,7 +2479,7 @@ int compileserverconfig(struct clsrvconf *conf, const char *block) { int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) { struct clsrvconf *conf, *resconf; - char *conftype = NULL, *rewriteinalias = NULL; + char *conftype = NULL, *rewriteinalias = NULL, *statusserver = NULL; long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN; uint8_t ipv4only = 0, ipv6only = 0, confmerged = 0; @@ -2477,10 +2494,11 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char conf->loopprevention = UCHAR_MAX; /* Uninitialized. */ resconf = (struct clsrvconf *)arg; if (resconf) { - conf->statusserver = resconf->statusserver; - conf->certnamecheck = resconf->certnamecheck; - } else - conf->certnamecheck = 1; + conf->statusserver = resconf->statusserver; + conf->certnamecheck = resconf->certnamecheck; + } else { + conf->certnamecheck = 1; + } if (!getgenericconfig(cf, block, "type", CONF_STR, &conftype, @@ -2499,7 +2517,7 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char "rewrite", CONF_STR, &rewriteinalias, "rewriteIn", CONF_STR, &conf->confrewritein, "rewriteOut", CONF_STR, &conf->confrewriteout, - "StatusServer", CONF_BLN, &conf->statusserver, + "StatusServer", CONF_STR, &statusserver, "RetryInterval", CONF_LINT, &retryinterval, "RetryCount", CONF_LINT, &retrycount, "DynamicLookupCommand", CONF_STR, &conf->dynamiclookupcommand, @@ -2575,6 +2593,19 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char conf->addttl = (uint8_t)addttl; } + if (statusserver) { + if (strcasecmp(statusserver, "Off") == 0) + conf->statusserver = RSP_STATSRV_OFF; + else if (strcasecmp(statusserver, "On") == 0) + conf->statusserver = RSP_STATSRV_ON; + else if (strcasecmp(statusserver, "Minimal") == 0) + conf->statusserver = RSP_STATSRV_MINIMAL; + else if (strcasecmp(statusserver, "Auto") == 0) + conf->statusserver = RSP_STATSRV_AUTO; + else + debugx(1, DBG_ERR, "config error in blocck %s: invalid StatusServer value: %s", block, statusserver); + } + if (resconf) { if (!mergesrvconf(resconf, conf)) goto errexit; @@ -2759,8 +2790,8 @@ void getmainconfig(const char *configfile) { "FTicksKey", CONF_STR, &fticks_key_str, "FTicksSyslogFacility", CONF_STR, &options.ftickssyslogfacility, "FTicksPrefix", CONF_STR, &options.fticksprefix, - "IPv4Only", CONF_BLN, &options.ipv4only, - "IPv6Only", CONF_BLN, &options.ipv6only, + "IPv4Only", CONF_BLN, &options.ipv4only, + "IPv6Only", CONF_BLN, &options.ipv6only, NULL )) debugx(1, DBG_ERR, "configuration error"); diff --git a/radsecproxy.conf.5 b/radsecproxy.conf.5 index a8b785b..10584f2 100644 --- a/radsecproxy.conf.5 +++ b/radsecproxy.conf.5 @@ -191,7 +191,7 @@ See \fIradsecproxy.conf\-example\fR for details. The FTicksMAC option has the same function as LogMAC for FTicks. The default for FTicksMAC is \fBVendorKeyHashed\fR which needs \fBFTicksKey\fR to be set. -Before chosing any of +Before choosing any of .BR Original , .BR FullyHashed or @@ -468,7 +468,7 @@ Apply the operations in the specified \fIrewrite\fR block on incoming (request) or outgoing (response) messages from this client. Rewriting incoming messages is done before, outgoing after other processing. If the \fBRewriteIn\fR is not configured, the rewrite blocks \fBdefaultClient\fR or \fBdefault\fR will be -applied if defined. No default blocks are appied for \fBRewriteOut\fR. +applied if defined. No default blocks are applied for \fBRewriteOut\fR. .RE .BI "RewriteAttribute User-Name:/" regex / replace / @@ -545,13 +545,18 @@ for the realm and then the SRV records for each NAPTR matching \&'x-eduroam:radius.tls' is provided in \fItools/naptr\-eduroam.sh\fR. .RE -.BR "StatusServer (" on | off ) +.BR "StatusServer (" on | off | minimal | auto ) .RS -Enable the use of status-server messages for this server (default off). If -statusserver is enabled, the proxy will send regular status-server messages to -the server to verify that it is alive. Status tracking of the server will solely -depend on status-server message and ignore lost requests. This should only be -enabled if the server supports it. +Enable the use of status-server messages for this server (default \fBoff\fR). If +statusserver is enabled (\fBon\fR), the proxy will send regular status-server +messages to the server to verify that it is alive. Status tracking of the server +will solely depend on status-server message and ignore lost requests. This +should only be enabled if the server supports it. With the option \fBminimal\fR +status-server messages are only sent when regular requests have been lost and no +other replies have been received. + +The option \fBauto\fR tries to detect whether the other server supports +status-server. If so, status-server messages are enabled in \fBminimal\fR mode. .RE .BI "RetryCount " count @@ -578,7 +583,7 @@ Apply the operations in the specified \fIrewrite\fR block on outgoing (request) or incoming (response) messages to/from this server. Rewriting outgoing messages is done after, incoming before other processing. If the \fBRewriteIn\fR is not configured, the rewrite blocks \fBdefaultServer\fR or \fBdefault\fR will be -applied if defined. No default blocks are appied for \fBRewriteOut\fR. +applied if defined. No default blocks are applied for \fBRewriteOut\fR. .RE .BR "LoopPrevention (" on | off) @@ -819,7 +824,7 @@ block are: .BI "AddAttribute " attribute \fR: value .RS -Add an \fIattribute\fR to the radius mesage and set it to \fIvalue\fR. The +Add an \fIattribute\fR to the radius message and set it to \fIvalue\fR. The \fIattribute\fR must be specified using the numerical attribute id. The \fIvalue\fR can either be numerical, a string, or a hex value. If the value starts with a number, it is interpreted as a 32bit unsigned integer. Use the ' diff --git a/radsecproxy.h b/radsecproxy.h index 5f7d4db..28c17d6 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -72,6 +72,13 @@ enum rsp_server_state { RSP_SERVER_STATE_FAILING }; +enum rsp_statsrv { + RSP_STATSRV_OFF = 0, + RSP_STATSRV_ON, + RSP_STATSRV_MINIMAL, + RSP_STATSRV_AUTO +}; + struct options { char *pidfile; char *logdestination; @@ -147,7 +154,7 @@ struct clsrvconf { char *confrewriteusername; struct modattr *rewriteusername; char *dynamiclookupcommand; - uint8_t statusserver; + enum rsp_statsrv statusserver; uint8_t retryinterval; uint8_t retrycount; uint8_t dupinterval; @@ -185,7 +192,7 @@ struct server { pthread_mutex_t lock; pthread_t clientth; uint8_t clientrdgone; - struct timeval lastconnecttry; + struct timeval connecttime; struct timeval lastreply; enum rsp_server_state state; uint8_t lostrqs; @@ -226,7 +233,7 @@ struct protodefs { void (*setprotoopts)(struct commonprotoopts *); char **(*getlistenerargs)(); void *(*listener)(void*); - int (*connecter)(struct server *, struct timeval *, int, char *); + int (*connecter)(struct server *, int, char *); void *(*clientconnreader)(void*); int (*clientradput)(struct server *, unsigned char *); void (*addclient)(struct client *); diff --git a/tcp.c b/tcp.c index 803a549..500abb2 100644 --- a/tcp.c +++ b/tcp.c @@ -29,7 +29,7 @@ static void setprotoopts(struct commonprotoopts *opts); static char **getlistenerargs(); void *tcplistener(void *arg); -int tcpconnect(struct server *server, struct timeval *when, int timeout, char * text); +int tcpconnect(struct server *server, int timeout, char * text); void *tcpclientrd(void *arg); int clientradputtcp(struct server *server, unsigned char *rad); void tcpsetsrcres(); @@ -79,8 +79,9 @@ void tcpsetsrcres() { AF_UNSPEC, NULL, protodefs.socktype); } -int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text) { - struct timeval now, start = {0,0}; +int tcpconnect(struct server *server, int timeout, char *text) { + struct timeval now, start; + int firsttry = 1; time_t wait; debug(DBG_DBG, "tcpconnect: called from %s", text); @@ -89,43 +90,27 @@ int tcpconnect(struct server *server, struct timeval *when, int timeout, char *t if (server->state == RSP_SERVER_STATE_CONNECTED) server->state = RSP_SERVER_STATE_RECONNECTING; - gettimeofday(&now, NULL); - if (when && (now.tv_sec - when->tv_sec) < 30 ) { - /* last connection was less than 30s ago. Delay next attempt */ - start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec); - } + gettimeofday(&start, NULL); for (;;) { if (server->sock >= 0) close(server->sock); server->sock = -1; - /* no sleep at startup or at first try */ - if (start.tv_sec) { - gettimeofday(&now, NULL); - wait = abs(now.tv_sec - start.tv_sec); - wait = wait > 60 ? 60 : wait; - - if (timeout && (now.tv_sec - start.tv_sec) > timeout) { - debug(DBG_DBG, "tlsconnect: timeout"); - pthread_mutex_unlock(&server->lock); - return 0; - } - - /* give up lock while sleeping for next try */ - pthread_mutex_unlock(&server->lock); - if (wait < 1) - sleep(2); - else { - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); - sleep(wait); - } - pthread_mutex_lock(&server->lock); - debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name); - } else { - gettimeofday(&start, NULL); + pthread_mutex_unlock(&server->lock); + wait = connect_wait(start, server->connecttime, firsttry); + debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + sleep(wait); + firsttry = 0; + + gettimeofday(&now, NULL); + if (timeout && (now.tv_sec - start.tv_sec) > timeout) { + debug(DBG_DBG, "tcpconnect: timeout"); + return 0; } + pthread_mutex_lock(&server->lock); + debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name); if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) < 0) continue; if (server->conf->keepalive) @@ -133,7 +118,7 @@ int tcpconnect(struct server *server, struct timeval *when, int timeout, char *t break; } server->state = RSP_SERVER_STATE_CONNECTED; - gettimeofday(&server->lastconnecttry, NULL); + gettimeofday(&server->connecttime, NULL); server->lostrqs = 0; pthread_mutex_unlock(&server->lock); pthread_mutex_lock(&server->newrq_mutex); @@ -230,16 +215,13 @@ int clientradputtcp(struct server *server, unsigned char *rad) { 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, server->dynamiclookuparg ? IDLE_TIMEOUT : 0); if (!buf) { if (server->dynamiclookuparg) break; - tcpconnect(server, &lastconnecttry, 0, "tcpclientrd"); + tcpconnect(server, 0, "tcpclientrd"); continue; } diff --git a/tests/Makefile.am b/tests/Makefile.am index a795140..a2dbce9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,5 +7,6 @@ LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ check_PROGRAMS = t_fticks t_rewrite t_resizeattr t_rewrite_config AM_CFLAGS = -g -Wall -Werror @SSL_CFLAGS@ @TARGET_CFLAGS@ LDADD = $(top_builddir)/librsp.a @SSL_LIBS@ +LDFLAGS = @SSL_LDFLAGS@ @TARGET_LDFLAGS@ TESTS = $(check_PROGRAMS) diff --git a/tls.c b/tls.c index 10622ac..85390c4 100644 --- a/tls.c +++ b/tls.c @@ -31,7 +31,7 @@ static void setprotoopts(struct commonprotoopts *opts); static char **getlistenerargs(); void *tlslistener(void *arg); -int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text); +int tlsconnect(struct server *server, int timeout, char *text); void *tlsclientrd(void *arg); int clientradputtls(struct server *server, unsigned char *rad); void tlssetsrcres(); @@ -82,9 +82,10 @@ void tlssetsrcres() { AF_UNSPEC, NULL, protodefs.socktype); } -int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) { - struct timeval now, start = {0,0}; +int tlsconnect(struct server *server, int timeout, char *text) { + struct timeval now, start; time_t wait; + int firsttry = 1; X509 *cert; SSL_CTX *ctx = NULL; unsigned long error; @@ -92,17 +93,10 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t debug(DBG_DBG, "tlsconnect: called from %s", text); pthread_mutex_lock(&server->lock); - if (server->state == RSP_SERVER_STATE_CONNECTED) server->state = RSP_SERVER_STATE_RECONNECTING; - pthread_mutex_unlock(&server->lock); - - gettimeofday(&now, NULL); - if (when && (now.tv_sec - when->tv_sec) < 30 ) { - /* last connection was less than 30s ago. Delay next attempt */ - start.tv_sec = now.tv_sec + 30 - (now.tv_sec - when->tv_sec); - } + gettimeofday(&start, NULL); for (;;) { /* ensure previous connection is properly closed */ @@ -114,29 +108,18 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t SSL_free(server->ssl); server->ssl = NULL; - /* no sleep at startup or at first try */ - if (start.tv_sec) { - gettimeofday(&now, NULL); - wait = abs(now.tv_sec - start.tv_sec); - wait = wait > 60 ? 60 : wait; - - if (timeout && (now.tv_sec - start.tv_sec) > timeout) { - debug(DBG_DBG, "tlsconnect: timeout"); - return 0; - } + wait = connect_wait(start, server->connecttime, firsttry); + debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); + sleep(wait); + firsttry = 0; - if (wait < 1) - sleep(2); - else { - debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait); - sleep(wait); - } - debug(DBG_INFO, "tlsconnect: retry connecting to %s", server->conf->name); - } else { - gettimeofday(&start, NULL); + gettimeofday(&now, NULL); + if (timeout && (now.tv_sec - start.tv_sec) > timeout) { + debug(DBG_DBG, "tlsconnect: timeout"); + return 0; } - /* done sleeping */ + debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name); if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) < 0) continue; if (server->conf->keepalive) @@ -181,7 +164,7 @@ int tlsconnect(struct server *server, struct timeval *when, int timeout, char *t pthread_mutex_lock(&server->lock); server->state = RSP_SERVER_STATE_CONNECTED; - gettimeofday(&server->lastconnecttry, NULL); + gettimeofday(&server->connecttime, NULL); server->lostrqs = 0; pthread_mutex_unlock(&server->lock); pthread_mutex_lock(&server->newrq_mutex); @@ -276,7 +259,7 @@ unsigned char *radtlsget(SSL *ssl, int timeout, pthread_mutex_t *lock) { len = RADLEN(buf); if (len < 20) { - debug(DBG_ERR, "radtlsget: length too small, malformed packet! closing conneciton!"); + debug(DBG_ERR, "radtlsget: length too small, malformed packet! closing connection!"); pthread_mutex_lock(lock); SSL_shutdown(ssl); pthread_mutex_unlock(lock); @@ -357,11 +340,9 @@ int clientradputtls(struct server *server, unsigned char *rad) { void *tlsclientrd(void *arg) { struct server *server = (struct server *)arg; unsigned char *buf; - struct timeval now, lastconnecttry; + struct timeval now; for (;;) { - /* yes, lastconnecttry is really necessary */ - lastconnecttry = server->lastconnecttry; buf = radtlsget(server->ssl, 10, &server->lock); if (!buf) { if (SSL_get_shutdown(server->ssl) || server->lostrqs) { @@ -371,7 +352,7 @@ void *tlsclientrd(void *arg) { debug (DBG_WARN, "tlsclientrd: server %s did not respond, closing connection.", server->conf->name); if (server->dynamiclookuparg) break; - tlsconnect(server, &lastconnecttry, 0, "tlsclientrd"); + tlsconnect(server, 0, "tlsclientrd"); } if (server->dynamiclookuparg) { gettimeofday(&now, NULL); diff --git a/tlscommon.c b/tlscommon.c index e429d12..7362309 100644 --- a/tlscommon.c +++ b/tlscommon.c @@ -44,9 +44,16 @@ static uint8_t cookie_secret_initialized = 0; #if OPENSSL_VERSION_NUMBER < 0x10100000 static pthread_mutex_t *ssl_locks = NULL; +#if OPENSSL_VERSION_NUMBER < 0x10000000 unsigned long ssl_thread_id() { return (unsigned long)pthread_self(); } +#else +void ssl_thread_id(CRYPTO_THREADID *id) { + CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self()); +} +#endif + void ssl_locking_callback(int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) @@ -69,7 +76,11 @@ void sslinit() { for (i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_init(&ssl_locks[i], NULL); } +#if OPENSSL_VERSION_NUMBER < 0x10000000 CRYPTO_set_id_callback(ssl_thread_id); +#else + CRYPTO_THREADID_set_callback(ssl_thread_id); +#endif CRYPTO_set_locking_callback(ssl_locking_callback); SSL_load_error_strings(); #else diff --git a/tools/radsec-dynsrv.sh b/tools/radsec-dynsrv.sh index 2c87a33..2eff080 100755 --- a/tools/radsec-dynsrv.sh +++ b/tools/radsec-dynsrv.sh @@ -5,7 +5,7 @@ # realm given as argument, and creates a server template based # on that. It currently ignores weight markers, but does sort # servers on priority marker, lowest number first. -# For host command this is coloumn 5, for dig it is coloumn 1. +# For host command this is column 5, for dig it is column 1. usage() { echo "Usage: ${0} " diff --git a/util.c b/util.c index df6f821..eadce8c 100644 --- a/util.c +++ b/util.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "debug.h" #include "util.h" @@ -129,15 +130,15 @@ void enable_keepalive(int socket) { debug(DBG_NOTICE, "TCP Keepalive feature might be limited on this platform"); #else optval = 3; - if(setsockopt(socket, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0) { + if(setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen) < 0) { debug(DBG_ERR, "enable_keepalive: setsockopt TCP_KEEPCNT failed"); } optval = 10; - if(setsockopt(socket, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) { + if(setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) { debug(DBG_ERR, "enable_keepalive: setsockopt TCP_KEEPIDLE %d failed", optval); } optval = 10; - if(setsockopt(socket, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) { + if(setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) { debug(DBG_ERR, "enable_keepalive: setsockopt TCP_KEEPINTVL failed"); } #endif @@ -251,6 +252,32 @@ int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout return s; } +time_t connect_wait(struct timeval attempt_start, struct timeval last_success, int firsttry) { + struct timeval now; + + gettimeofday(&now, NULL); + + if (attempt_start.tv_sec < last_success.tv_sec || + attempt_start.tv_sec > now.tv_sec) { + debug(DBG_WARN, "connect_wait: invalid timers detected!"); + return 60; + } + + if (now.tv_sec - last_success.tv_sec < 30) + return 30 - (attempt_start.tv_sec - last_success.tv_sec); + + if (firsttry) + return 0; + + if (now.tv_sec - attempt_start.tv_sec < 2) + return 2; + + if (now.tv_sec - attempt_start.tv_sec > 60) + return 60; + + return now.tv_sec - attempt_start.tv_sec; +} + /* Local Variables: */ /* c-file-style: "stroustrup" */ /* End: */ diff --git a/util.h b/util.h index 3daad3d..68b1f24 100644 --- a/util.h +++ b/util.h @@ -23,6 +23,7 @@ void disable_DF_bit(int socket, struct addrinfo *res); void enable_keepalive(int socket); int bindtoaddr(struct addrinfo *addrinfo, int family, int reuse); int connecttcp(struct addrinfo *addrinfo, struct addrinfo *src, uint16_t timeout); +time_t connect_wait(struct timeval attempt_start, struct timeval last_success, int firsttry); /* Local Variables: */