diff options
Diffstat (limited to 'src/rfc1035.c')
-rw-r--r-- | src/rfc1035.c | 88 |
1 files changed, 71 insertions, 17 deletions
diff --git a/src/rfc1035.c b/src/rfc1035.c index 60ef272..d6d3b49 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1360,8 +1360,15 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int #undef CHECK_LIMIT } +static int crec_isstale(struct crec *crecp, time_t now) +{ + return (!(crecp->flags & F_IMMORTAL)) && difftime(crecp->ttd, now) < 0; +} + static unsigned long crec_ttl(struct crec *crecp, time_t now) { + signed long ttl = difftime(crecp->ttd, now); + /* Return 0 ttl for DHCP entries, which might change before the lease expires, unless configured otherwise. */ @@ -1370,8 +1377,8 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl; /* Apply ceiling of actual lease length to configured TTL. */ - if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl) - return crecp->ttd - now; + if (!(crecp->flags & F_IMMORTAL) && ttl < conf_ttl) + return ttl; return conf_ttl; } @@ -1380,9 +1387,13 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) if (crecp->flags & F_IMMORTAL) return crecp->ttd; + /* Stale cache entries. */ + if (ttl < 0) + return 0; + /* Return the Max TTL value if it is lower than the actual TTL */ - if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl)) - return crecp->ttd - now; + if (daemon->max_ttl == 0 || ((unsigned)ttl < daemon->max_ttl)) + return ttl; else return daemon->max_ttl; } @@ -1395,7 +1406,8 @@ static int cache_validated(const struct crec *crecp) /* return zero if we can't answer from cache, or packet size if we can */ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, - time_t now, int ad_reqd, int do_bit, int have_pseudoheader) + time_t now, int ad_reqd, int do_bit, int have_pseudoheader, + int *stale) { char *name = daemon->namebuff; unsigned char *p, *ansp; @@ -1411,6 +1423,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t len; int rd_bit = (header->hb3 & HB3_RD); + if (stale) + *stale = 0; + /* never answer queries with RD unset, to avoid cache snooping. */ if (ntohs(header->ancount) != 0 || ntohs(header->nscount) != 0 || @@ -1459,13 +1474,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_NXDOMAIN))) { char *cname_target; - + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + if (crecp->flags & F_NXDOMAIN) { if (qtype == T_CNAME) { if (!dryrun) - log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0); + log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0); auth = 0; nxdomain = 1; ans = 1; @@ -1487,7 +1511,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (!dryrun) { - log_query(crecp->flags, name, NULL, record_source(crecp->uid), 0); + log_query(stale_flag | crecp->flags, name, NULL, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, T_CNAME, C_IN, "d", cname_target)) @@ -1656,22 +1680,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, { do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */ if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP))) continue; + if (!(crecp->flags & F_DNSSECOK)) sec_data = 0; - + ans = 1; - + if (crecp->flags & F_NEG) { auth = 0; if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL, 0); + log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0); } else { @@ -1679,7 +1714,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, auth = 0; if (!dryrun) { - log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, + log_query(stale_flag | (crecp->flags & ~F_FORWARD), cache_get_name(crecp), &addr, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, @@ -1788,7 +1823,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if ((crecp = cache_find_by_name(NULL, name, now, flag | F_NXDOMAIN | (dryrun ? F_NO_RR : 0)))) { int localise = 0; - + /* See if a putative address is on the network from which we received the query, is so we'll filter other answers. */ if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4) @@ -1810,6 +1845,16 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, (rd_bit && (!do_bit || cache_validated(crecp)) )) do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } + /* don't answer wildcard queries with data not from /etc/hosts or DHCP leases */ if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) @@ -1825,7 +1870,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); } else { @@ -1842,7 +1887,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ans = 1; if (!dryrun) { - log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, + log_query(stale_flag | (crecp->flags & ~F_REVERSE), name, &crecp->addr, record_source(crecp->uid), 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, @@ -1953,6 +1998,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))) do { + int stale_flag = 0; + + if (crec_isstale(crecp, now)) + { + if (stale) + *stale = 1; + + stale_flag = F_STALE; + } /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases, except for NXDOMAIN */ if (qtype == T_ANY && !(crecp->flags & (F_NXDOMAIN))) break; @@ -1968,12 +2022,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_NXDOMAIN) nxdomain = 1; if (!dryrun) - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); } else if (!dryrun) { char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL); - log_query(crecp->flags, name, NULL, NULL, 0); + log_query(stale_flag | crecp->flags, name, NULL, NULL, 0); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd", |