diff options
-rw-r--r-- | usr.sbin/rebound/rebound.c | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/usr.sbin/rebound/rebound.c b/usr.sbin/rebound/rebound.c index 0f560e9f771..aabfdeb9bf8 100644 --- a/usr.sbin/rebound/rebound.c +++ b/usr.sbin/rebound/rebound.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rebound.c,v 1.67 2016/08/21 21:23:48 tedu Exp $ */ +/* $OpenBSD: rebound.c,v 1.68 2016/09/01 10:54:36 tedu Exp $ */ /* * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> * @@ -29,6 +29,7 @@ #include <syslog.h> #include <stdlib.h> #include <stdio.h> +#include <limits.h> #include <string.h> #include <err.h> #include <unistd.h> @@ -37,6 +38,8 @@ #include <getopt.h> #include <stdarg.h> +#define MINIMUM(a,b) (((a)<(b))?(a):(b)) + uint16_t randomid(void); union sockthing { @@ -60,14 +63,6 @@ struct dnspacket { /* ... */ }; -struct dnsrr { - uint16_t type; - uint16_t class; - uint32_t ttl; - uint16_t rdatalen; - /* ... */ -}; - /* * requests will point to cache entries until a response is received. * until then, the request owns the entry and must free it. @@ -302,6 +297,50 @@ fail: return NULL; } +static uint32_t +minttl(struct dnspacket *resp, size_t rlen) +{ + uint32_t minttl = UINT_MAX, ttl, cnt, i; + uint16_t len; + char *p = (char *)resp; + char *end = p + rlen; + + /* skip past packet header */ + p += sizeof(struct dnspacket); + if (p >= end) + return -1; + if (ntohs(resp->qdcount) != 1) + return -1; + /* skip past query name, type, and class */ + p += strnlen(p, end - p); + p += 2; + p += 2; + cnt = ntohs(resp->ancount); + for (i = 0; i < cnt; i++) { + if (p >= end) + return -1; + /* skip past answer name, type, and class */ + p += strnlen(p, end - p); + p += 2; + p += 2; + if (p + 4 >= end) + return -1; + memcpy(&ttl, p, 4); + p += 4; + if (p + 2 >= end) + return -1; + ttl = ntohl(ttl); + if (ttl < minttl) + minttl = ttl; + memcpy(&len, p, 2); + p += 2; + p += ntohs(len); + } + return minttl; +} + + + static void sendreply(int ud, struct request *req) { @@ -309,6 +348,7 @@ sendreply(int ud, struct request *req) struct dnspacket *resp; struct dnscache *ent; size_t r; + uint32_t ttl; resp = (struct dnspacket *)buf; @@ -327,8 +367,11 @@ sendreply(int ud, struct request *req) */ if (RB_INSERT(cachetree, &cachetree, ent)) return; + ttl = minttl(resp, r); + if (ttl == -1) + ttl = 0; ent->ts = now; - ent->ts.tv_sec += 10; + ent->ts.tv_sec += MINIMUM(ttl, 300); ent->resp = malloc(r); if (!ent->resp) { RB_REMOVE(cachetree, &cachetree, ent); |