-/* $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 <tedu@openbsd.org>
*
struct dnspacket *resp;
size_t resplen;
struct timespec ts;
+ struct timespec basetime;
};
static TAILQ_HEAD(, dnscache) cachefifo;
static RB_HEAD(cachetree, dnscache) cachetree;
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)
{
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
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);