From 5d5e4e2fa31d670235860579f4f77f7e5e9dfa9b Mon Sep 17 00:00:00 2001 From: tteras Date: Fri, 23 Jan 2009 08:25:06 +0000 Subject: [PATCH] Detect if monotonic system clock is available, and use it for relative time measurements to avoid complite hang if time jumps backwards. --- crypto/dist/ipsec-tools/configure.ac | 10 ++ crypto/dist/ipsec-tools/src/racoon/handler.c | 32 +++-- crypto/dist/ipsec-tools/src/racoon/handler.h | 6 +- .../dist/ipsec-tools/src/racoon/isakmp_inf.c | 6 +- .../ipsec-tools/src/racoon/isakmp_xauth.c | 4 +- crypto/dist/ipsec-tools/src/racoon/schedule.c | 112 +++++++++--------- crypto/dist/ipsec-tools/src/racoon/schedule.h | 33 ++++-- crypto/dist/ipsec-tools/src/racoon/throttle.c | 69 +++++------ crypto/dist/ipsec-tools/src/racoon/throttle.h | 6 +- 9 files changed, 140 insertions(+), 138 deletions(-) diff --git a/crypto/dist/ipsec-tools/configure.ac b/crypto/dist/ipsec-tools/configure.ac index 586920cbe9e3..daca418e2e67 100644 --- a/crypto/dist/ipsec-tools/configure.ac +++ b/crypto/dist/ipsec-tools/configure.ac @@ -784,6 +784,16 @@ if test "$enable_security_context" = "yes"; then fi fi +RACOON_PATH_LIBS([clock_gettime], [rt]) + +AC_MSG_CHECKING(for monotonic system clock) +AC_TRY_COMPILE( + [#include ], + [clock_gettime(CLOCK_MONOTONIC, NULL);], + [AC_DEFINE([HAVE_CLOCK_MONOTONIC], [], [Have a monotonic clock]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + CFLAGS="$CFLAGS $CFLAGS_ADD" CPPFLAGS="$CPPFLAGS $CPPFLAGS_ADD" diff --git a/crypto/dist/ipsec-tools/src/racoon/handler.c b/crypto/dist/ipsec-tools/src/racoon/handler.c index 2430a625eb91..816db24ea781 100644 --- a/crypto/dist/ipsec-tools/src/racoon/handler.c +++ b/crypto/dist/ipsec-tools/src/racoon/handler.c @@ -1,4 +1,4 @@ -/* $NetBSD: handler.c,v 1.23 2008/12/23 14:03:12 tteras Exp $ */ +/* $NetBSD: handler.c,v 1.24 2009/01/23 08:25:06 tteras Exp $ */ /* Id: handler.c,v 1.28 2006/05/26 12:17:29 manubsd Exp */ @@ -342,7 +342,6 @@ newph1() #ifdef ENABLE_DPD iph1->dpd_support = 0; - iph1->dpd_lastack = 0; iph1->dpd_seq = 0; iph1->dpd_fails = 0; #endif @@ -960,12 +959,9 @@ check_recvdpkt(remote, local, rbuf) { vchar_t *hash; struct recvdpkt *r; - time_t t; + struct timeval now, diff; int len, s; - /* set current time */ - t = time(NULL); - hash = eay_md5_one(rbuf); if (!hash) { plog(LLV_ERROR, LOCATION, NULL, @@ -995,7 +991,9 @@ check_recvdpkt(remote, local, rbuf) */ /* check the previous time to send */ - if (t - r->time_send < 1) { + sched_get_monotonic_time(&now); + timersub(&now, &r->time_send, &diff); + if (diff.tv_sec == 0) { plog(LLV_WARNING, LOCATION, NULL, "the packet retransmitted in a short time from %s\n", saddr2str(remote)); @@ -1024,7 +1022,7 @@ check_recvdpkt(remote, local, rbuf) "deleted the retransmission packet to %s.\n", saddr2str(remote)); } else - r->time_send = t; + r->time_send = now; return 1; } @@ -1081,8 +1079,7 @@ add_recvdpkt(remote, local, sbuf, rbuf) } new->retry_counter = lcconf->retry_counter; - new->time_send = 0; - new->created = time(NULL); + sched_get_monotonic_time(&new->time_send); LIST_INSERT_HEAD(&rcptree, new, chain); @@ -1116,24 +1113,25 @@ sweep_recvdpkt(dummy) struct sched *dummy; { struct recvdpkt *r, *next; - time_t t, lt; + struct timeval now, diff, sweep; - /* set current time */ - t = time(NULL); + sched_get_monotonic_time(&now); - /* set the lifetime of the retransmission */ - lt = lcconf->retry_counter * lcconf->retry_interval; + /* calculate sweep time; delete entries older than this */ + diff.tv_sec = lcconf->retry_counter * lcconf->retry_interval; + diff.tv_usec = 0; + timersub(&now, &diff, &sweep); for (r = LIST_FIRST(&rcptree); r; r = next) { next = LIST_NEXT(r, chain); - if (t - r->created > lt) { + if (timercmp(&r->time_send, &sweep, <)) { rem_recvdpkt(r); del_recvdpkt(r); } } - sched_schedule(&sc_sweep, lt, sweep_recvdpkt); + sched_schedule(&sc_sweep, diff.tv_sec, sweep_recvdpkt); } void diff --git a/crypto/dist/ipsec-tools/src/racoon/handler.h b/crypto/dist/ipsec-tools/src/racoon/handler.h index 0ac83ba3f5d7..c0635fb0c876 100644 --- a/crypto/dist/ipsec-tools/src/racoon/handler.h +++ b/crypto/dist/ipsec-tools/src/racoon/handler.h @@ -1,4 +1,4 @@ -/* $NetBSD: handler.h,v 1.18 2009/01/23 08:06:56 tteras Exp $ */ +/* $NetBSD: handler.h,v 1.19 2009/01/23 08:25:06 tteras Exp $ */ /* Id: handler.h,v 1.19 2006/02/25 08:25:12 manubsd Exp */ @@ -202,7 +202,6 @@ struct ph1handle { #ifdef ENABLE_DPD int dpd_support; /* Does remote supports DPD ? */ - time_t dpd_lastack; /* Last ack received */ u_int16_t dpd_seq; /* DPD seq number to receive */ u_int8_t dpd_fails; /* number of failures */ struct sched dpd_r_u; @@ -379,8 +378,7 @@ struct recvdpkt { vchar_t *hash; /* hash of the received packet */ vchar_t *sendbuf; /* buffer for the response */ int retry_counter; /* how many times to send */ - time_t time_send; /* timestamp to send a packet */ - time_t created; /* timestamp to create a queue */ + struct timeval time_send; /* timestamp of previous send */ LIST_ENTRY(recvdpkt) chain; }; diff --git a/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c b/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c index d3de5480d071..722a4f63e080 100644 --- a/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c +++ b/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_inf.c,v 1.35 2008/12/23 14:03:12 tteras Exp $ */ +/* $NetBSD: isakmp_inf.c,v 1.36 2009/01/23 08:25:06 tteras Exp $ */ /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */ @@ -1556,10 +1556,6 @@ isakmp_info_recv_r_u_ack (iph1, ru, msgid) } iph1->dpd_fails = 0; - - /* Useless ??? */ - iph1->dpd_lastack = time(NULL); - sched_cancel(&iph1->dpd_r_u); isakmp_sched_r_u(iph1, 0); diff --git a/crypto/dist/ipsec-tools/src/racoon/isakmp_xauth.c b/crypto/dist/ipsec-tools/src/racoon/isakmp_xauth.c index 2e620f85ce97..69fcd345e6f5 100644 --- a/crypto/dist/ipsec-tools/src/racoon/isakmp_xauth.c +++ b/crypto/dist/ipsec-tools/src/racoon/isakmp_xauth.c @@ -1,4 +1,4 @@ -/* $NetBSD: isakmp_xauth.c,v 1.18 2009/01/23 08:23:51 tteras Exp $ */ +/* $NetBSD: isakmp_xauth.c,v 1.19 2009/01/23 08:25:06 tteras Exp $ */ /* Id: isakmp_xauth.c,v 1.38 2006/08/22 18:17:17 manubsd Exp */ @@ -312,7 +312,7 @@ xauth_attr_reply(iph1, attr, id) * On failure, throttle the connexion for the remote host * in order to make password attacks more difficult. */ - throttle_delay = throttle_host(iph1->remote, res) - time(NULL); + throttle_delay = throttle_host(iph1->remote, res); if (throttle_delay > 0) { char *str; diff --git a/crypto/dist/ipsec-tools/src/racoon/schedule.c b/crypto/dist/ipsec-tools/src/racoon/schedule.c index 1644583e60b1..8776bfd7eff8 100644 --- a/crypto/dist/ipsec-tools/src/racoon/schedule.c +++ b/crypto/dist/ipsec-tools/src/racoon/schedule.c @@ -1,4 +1,4 @@ -/* $NetBSD: schedule.c,v 1.5 2008/09/19 11:01:08 tteras Exp $ */ +/* $NetBSD: schedule.c,v 1.6 2009/01/23 08:25:07 tteras Exp $ */ /* $KAME: schedule.c,v 1.19 2001/11/05 10:53:19 sakane Exp $ */ @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -52,24 +53,46 @@ #include "var.h" #include "gcmalloc.h" -#define FIXY2038PROBLEM - #ifndef TAILQ_FOREACH #define TAILQ_FOREACH(elm, head, field) \ for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field)) #endif -static struct timeval timeout; - -#ifdef FIXY2038PROBLEM -#define Y2038TIME_T 0x7fffffff -static time_t launched; /* time when the program launched. */ -static time_t deltaY2038; -#endif - static TAILQ_HEAD(_schedtree, sched) sctree; -static time_t current_time __P((void)); +void +sched_get_monotonic_time(tv) + struct timeval *tv; +{ +#ifdef HAVE_CLOCK_MONOTONIC + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; +#else + gettimeofday(tv, NULL); +#endif +} + +time_t +sched_monotonic_to_time_t(tv, now) + struct timeval *tv, *now; +{ +#ifdef HAVE_CLOCK_MONOTONIC + struct timeval mynow, res; + + if (now == NULL) { + sched_get_monotonic_time(&mynow); + now = &mynow; + } + timersub(now, tv, &res); + + return time(NULL) + res.tv_sec; +#else + return tv->tv_sec; +#endif +} /* * schedule handler @@ -80,11 +103,13 @@ static time_t current_time __P((void)); struct timeval * schedular() { - time_t now, delta; + static struct timeval timeout; + struct timeval now; struct sched *p; - now = current_time(); - while (!TAILQ_EMPTY(&sctree) && TAILQ_FIRST(&sctree)->xtime <= now) { + sched_get_monotonic_time(&now); + while (!TAILQ_EMPTY(&sctree) && + timercmp(&TAILQ_FIRST(&sctree)->xtime, &now, <=)) { void (*func)(struct sched *); p = TAILQ_FIRST(&sctree); @@ -97,10 +122,8 @@ schedular() if (p == NULL) return NULL; - now = current_time(); - delta = p->xtime - now; - timeout.tv_sec = delta < 0 ? 0 : delta; - timeout.tv_usec = 0; + sched_get_monotonic_time(&now); + timersub(&p->xtime, &now, &timeout); return &timeout; } @@ -116,17 +139,20 @@ sched_schedule(sc, tick, func) { static long id = 1; struct sched *p; + struct timeval now; sched_cancel(sc); + sc->func = func; sc->id = id++; - time(&sc->created); - sc->tick = tick; - sc->xtime = current_time() + tick; + sc->tick.tv_sec = tick; + sc->tick.tv_usec = 0; + sched_get_monotonic_time(&now); + timeradd(&now, &sc->tick, &sc->xtime); /* add to schedule table */ TAILQ_FOREACH(p, &sctree, chain) { - if (sc->xtime < p->xtime) + if (timercmp(&sc->xtime, &p->xtime, <)) break; } if (p == NULL) @@ -148,29 +174,6 @@ sched_cancel(sc) } } - -/* get current time. - * if defined FIXY2038PROBLEM, base time is the time when called sched_init(). - * Otherwise, conform to time(3). - */ -static time_t -current_time() -{ - time_t n; -#ifdef FIXY2038PROBLEM - time_t t; - - time(&n); - t = n - launched; - if (t < 0) - t += deltaY2038; - - return t; -#else - return time(&n); -#endif -} - /* * for debug */ @@ -182,6 +185,7 @@ sched_dump(buf, len) caddr_t new; struct sched *p; struct scheddump *dst; + struct timeval now, created; int cnt = 0; /* initialize */ @@ -202,12 +206,14 @@ sched_dump(buf, len) return -1; dst = (struct scheddump *)new; - p = TAILQ_FIRST(&sctree); + sched_get_monotonic_time(&now); + p = TAILQ_FIRST(&sctree); while (p) { - dst->xtime = p->xtime; + timersub(&p->xtime, &p->tick, &created); + dst->xtime = p->xtime.tv_sec; dst->id = p->id; - dst->created = p->created; - dst->tick = p->tick; + dst->created = sched_monotonic_to_time_t(&created, &now); + dst->tick = p->tick.tv_sec; p = TAILQ_NEXT(p, chain); if (p == NULL) @@ -224,12 +230,6 @@ sched_dump(buf, len) void sched_init() { -#ifdef FIXY2038PROBLEM - time(&launched); - - deltaY2038 = Y2038TIME_T - launched; -#endif - TAILQ_INIT(&sctree); } diff --git a/crypto/dist/ipsec-tools/src/racoon/schedule.h b/crypto/dist/ipsec-tools/src/racoon/schedule.h index 667a51d2b90b..87f1799a8b0d 100644 --- a/crypto/dist/ipsec-tools/src/racoon/schedule.h +++ b/crypto/dist/ipsec-tools/src/racoon/schedule.h @@ -1,4 +1,4 @@ -/* $NetBSD: schedule.h,v 1.6 2008/09/19 11:01:08 tteras Exp $ */ +/* $NetBSD: schedule.h,v 1.7 2009/01/23 08:25:07 tteras Exp $ */ /* Id: schedule.h,v 1.5 2006/05/03 21:53:42 vanhu Exp */ @@ -36,6 +36,16 @@ #define _SCHEDULE_H #include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif #include "gnuc.h" #ifndef offsetof @@ -56,21 +66,14 @@ /* scheduling table */ /* the head is the nearest event. */ struct sched { - time_t xtime; /* event time which is as time(3). */ - /* - * if defined FIXY2038PROBLEM, this time - * is from the time when called sched_init(). - */ - void (*func) __P((struct sched *)); /* call this function when timeout. */ - - long id; /* for debug */ - time_t created; /* for debug */ - time_t tick; /* for debug */ - + void (*func) __P((struct sched *)); /* callback on timeout */ + struct timeval xtime; /* expiration time */ + struct timeval tick; /* relative timeout */ TAILQ_ENTRY(sched) chain; + long id; /* for debug */ }; -#define SCHED_INITIALIZER() { 0, NULL, } +#define SCHED_INITIALIZER() { NULL, } struct scheddump { time_t xtime; @@ -79,6 +82,10 @@ struct scheddump { time_t tick; }; +time_t sched_monotonic_to_time_t __P((struct timeval *tv, + struct timeval *now)); +void sched_get_monotonic_time __P((struct timeval *tv)); + struct timeval *schedular __P((void)); void sched_schedule __P((struct sched *, time_t, void (*func) __P((struct sched *)))); diff --git a/crypto/dist/ipsec-tools/src/racoon/throttle.c b/crypto/dist/ipsec-tools/src/racoon/throttle.c index cd7de1f38818..5c5fe1bd888b 100644 --- a/crypto/dist/ipsec-tools/src/racoon/throttle.c +++ b/crypto/dist/ipsec-tools/src/racoon/throttle.c @@ -1,4 +1,4 @@ -/* $NetBSD: throttle.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: throttle.c,v 1.5 2009/01/23 08:25:07 tteras Exp $ */ /* Id: throttle.c,v 1.5 2006/04/05 20:54:50 manubsd Exp */ @@ -33,23 +33,10 @@ #include "config.h" -#include #include #include -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif #include #include -#include - #include #include @@ -58,21 +45,21 @@ #include "plog.h" #include "throttle.h" #include "sockmisc.h" -#include "libpfkey.h" #include "isakmp_var.h" #include "isakmp.h" #include "isakmp_xauth.h" #include "isakmp_cfg.h" #include "gcmalloc.h" -struct throttle_list throttle_list = TAILQ_HEAD_INITIALIZER(throttle_list); - +static struct throttle_list throttle_list = + TAILQ_HEAD_INITIALIZER(throttle_list); struct throttle_entry * throttle_add(addr) struct sockaddr *addr; { struct throttle_entry *te; + struct timeval now, penalty; size_t len; len = sizeof(*te) @@ -82,7 +69,11 @@ throttle_add(addr) if ((te = racoon_malloc(len)) == NULL) return NULL; - te->penalty = time(NULL) + isakmp_cfg_config.auth_throttle; + sched_get_monotonic_time(&now); + penalty.tv_sec = isakmp_cfg_config.auth_throttle; + penalty.tv_usec = 0; + timeradd(&now, &penalty, &te->penalty_ends); + memcpy(&te->host, addr, sysdep_sa_len(addr)); TAILQ_INSERT_HEAD(&throttle_list, te, next); @@ -95,25 +86,24 @@ throttle_host(addr, authfail) int authfail; { struct throttle_entry *te; + struct timeval now, res; int found = 0; - time_t now; if (isakmp_cfg_config.auth_throttle == 0) return 0; - now = time(NULL); - + sched_get_monotonic_time(&now); restart: RACOON_TAILQ_FOREACH_REVERSE(te, &throttle_list, throttle_list, next) { - /* - * Remove outdated entries - */ - if (te->penalty < now) { + /* + * Remove outdated entries + */ + if (timercmp(&te->penalty_ends, &now, <)) { TAILQ_REMOVE(&throttle_list, te, next); racoon_free(te); goto restart; } - + if (cmpsaddrwop(addr, (struct sockaddr *)&te->host) == 0) { found = 1; break; @@ -130,8 +120,7 @@ restart: if ((te = throttle_add(addr)) == NULL) { plog(LLV_ERROR, LOCATION, NULL, "Throttle insertion failed\n"); - return (time(NULL) - + isakmp_cfg_config.auth_throttle); + return isakmp_cfg_config.auth_throttle; } } return 0; @@ -140,19 +129,21 @@ restart: * We had a match and auth failed, increase penalty. */ if (authfail) { - time_t remaining; - time_t new; + struct timeval remaining, penalty; - remaining = te->penalty - now; - new = remaining + isakmp_cfg_config.auth_throttle; - - if (new > THROTTLE_PENALTY_MAX) - new = THROTTLE_PENALTY_MAX; - - te->penalty = now + new; + timersub(&te->penalty_ends, &now, &remaining); + penalty.tv_sec = isakmp_cfg_config.auth_throttle; + penalty.tv_usec = 0; + timeradd(&penalty, &remaining, &res); + if (res.tv_sec >= THROTTLE_PENALTY_MAX) { + res.tv_sec = THROTTLE_PENALTY_MAX; + res.tv_usec = 0; + } + timeradd(&now, &res, &te->penalty_ends); } } - - return te->penalty; + + timersub(&te->penalty_ends, &now, &res); + return res.tv_sec; } diff --git a/crypto/dist/ipsec-tools/src/racoon/throttle.h b/crypto/dist/ipsec-tools/src/racoon/throttle.h index baa9af5552b8..54a8ed187d4a 100644 --- a/crypto/dist/ipsec-tools/src/racoon/throttle.h +++ b/crypto/dist/ipsec-tools/src/racoon/throttle.h @@ -1,4 +1,4 @@ -/* $NetBSD: throttle.h,v 1.4 2006/09/09 16:22:10 manu Exp $ */ +/* $NetBSD: throttle.h,v 1.5 2009/01/23 08:25:07 tteras Exp $ */ /* Id: throttle.h,v 1.1 2004/11/30 00:46:09 manubsd Exp */ @@ -34,8 +34,10 @@ #ifndef _THROTTLE_H #define _THROTTLE_H +#include "schedule.h" + struct throttle_entry { - int penalty; + struct timeval penalty_ends; TAILQ_ENTRY(throttle_entry) next; struct sockaddr_storage host; };