From c569e7755ace1e95a2130ae08fdaf43800ff9617 Mon Sep 17 00:00:00 2001 From: tedu Date: Tue, 4 Jul 2017 00:30:45 +0000 Subject: [PATCH] properly adjust the ttl of replies instead of freezing them in time --- usr.sbin/rebound/rebound.c | 61 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/usr.sbin/rebound/rebound.c b/usr.sbin/rebound/rebound.c index 03c93332472..40b4e4a9b04 100644 --- a/usr.sbin/rebound/rebound.c +++ b/usr.sbin/rebound/rebound.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rebound.c,v 1.86 2017/07/03 16:36:48 tedu Exp $ */ +/* $OpenBSD: rebound.c,v 1.87 2017/07/04 00:30:45 tedu Exp $ */ /* * Copyright (c) 2015 Ted Unangst * @@ -82,6 +82,7 @@ struct dnscache { struct dnspacket *resp; size_t resplen; struct timespec ts; + struct timespec basetime; }; static TAILQ_HEAD(, dnscache) cachefifo; static RB_HEAD(cachetree, dnscache) cachetree; @@ -201,6 +202,61 @@ freecacheent(struct dnscache *ent) free(ent); } +static int +adjustttl(struct dnscache *ent) +{ + struct dnspacket *resp = ent->resp; + char *p = (char *)resp; + u_int rlen = ent->resplen; + u_int used = 0; + uint32_t ttl, cnt, i; + uint16_t len; + time_t diff; + + diff = now.tv_sec - ent->basetime.tv_sec; + if (diff <= 0) + return 0; + + /* checks are redundant; checked when cacheent is created */ + /* skip past packet header */ + used += sizeof(struct dnspacket); + if (used >= rlen) + return -1; + if (ntohs(resp->qdcount) != 1) + return -1; + /* skip past query name, type, and class */ + used += strnlen(p + used, rlen - used); + used += 2; + used += 2; + cnt = ntohs(resp->ancount); + for (i = 0; i < cnt; i++) { + if (used >= rlen) + return -1; + /* skip past answer name, type, and class */ + used += strnlen(p + used, rlen - used); + used += 2; + used += 2; + if (used + 4 >= rlen) + return -1; + memcpy(&ttl, p + used, 4); + ttl = ntohl(ttl); + /* expired */ + if (diff >= ttl) + return -1; + ttl -= diff; + ttl = ntohl(ttl); + memcpy(p + used, &ttl, 4); + used += 4; + if (used + 2 >= rlen) + return -1; + memcpy(&len, p + used, 2); + used += 2; + used += ntohs(len); + } + ent->basetime.tv_sec += diff; + return 0; +} + static struct dnscache * cachelookup(struct dnspacket *dnsreq, size_t reqlen) { @@ -224,7 +280,7 @@ cachelookup(struct dnspacket *dnsreq, size_t reqlen) key.req = dnsreq; hit = RB_FIND(cachetree, &cachetree, &key); if (hit) { - if (timespeccmp(&hit->ts, &now, <=)) { + if (adjustttl(hit) != 0) { freecacheent(hit); hit = NULL; } else @@ -446,6 +502,7 @@ sendreply(struct request *req) return; ent->ts = now; ent->ts.tv_sec += MINIMUM(ttl, 300); + ent->basetime = now; ent->resp = malloc(r); if (!ent->resp) { RB_REMOVE(cachetree, &cachetree, ent); -- 2.20.1