Commit cbc65242 authored by Simon Kelley's avatar Simon Kelley

Make caching work for CNAMEs pointing to A/AAAA records shadowed in /etc/hosts

If the answer to an upstream query is a CNAME which points to an
A/AAAA record which also exists in /etc/hosts and friends, then
caching is suppressed, to avoid inconsistent answers. This is
now modified to allow caching when the upstream and local A/AAAA
records have the same value.
parent 094b5c3d
...@@ -322,7 +322,7 @@ static int is_expired(time_t now, struct crec *crecp) ...@@ -322,7 +322,7 @@ static int is_expired(time_t now, struct crec *crecp)
return 1; return 1;
} }
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
{ {
/* Scan and remove old entries. /* Scan and remove old entries.
If (flags & F_FORWARD) then remove any forward entries for name and any expired If (flags & F_FORWARD) then remove any forward entries for name and any expired
...@@ -331,8 +331,8 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -331,8 +331,8 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
entries in the whole cache. entries in the whole cache.
If (flags == 0) remove any expired entries in the whole cache. If (flags == 0) remove any expired entries in the whole cache.
In the flags & F_FORWARD case, the return code is valid, and returns zero if the In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
name exists in the cache as a HOSTS or DHCP entry (these are never deleted) to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal> We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
so that when we hit an entry which isn't reverse and is immortal, we're done. */ so that when we hit an entry which isn't reverse and is immortal, we're done. */
...@@ -361,7 +361,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -361,7 +361,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
{ {
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
return 0; return crecp;
*up = crecp->hash_next; *up = crecp->hash_next;
cache_unlink(crecp); cache_unlink(crecp);
cache_free(crecp); cache_free(crecp);
...@@ -378,7 +378,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -378,7 +378,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
crecp->addr.sig.type_covered == addr->addr.dnssec.type)) crecp->addr.sig.type_covered == addr->addr.dnssec.type))
{ {
if (crecp->flags & F_CONFIG) if (crecp->flags & F_CONFIG)
return 0; return crecp;
*up = crecp->hash_next; *up = crecp->hash_next;
cache_unlink(crecp); cache_unlink(crecp);
cache_free(crecp); cache_free(crecp);
...@@ -423,7 +423,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign ...@@ -423,7 +423,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
up = &crecp->hash_next; up = &crecp->hash_next;
} }
return 1; return NULL;
} }
/* Note: The normal calling sequence is /* Note: The normal calling sequence is
...@@ -471,10 +471,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr, ...@@ -471,10 +471,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
return NULL; return NULL;
/* First remove any expired entries and entries for the name/address we /* First remove any expired entries and entries for the name/address we
are currently inserting. Fail if we attempt to delete a name from are currently inserting. */
/etc/hosts or DHCP. */ if ((new = cache_scan_free(name, addr, now, flags)))
if (!cache_scan_free(name, addr, now, flags)) {
{ /* We're trying to insert a record over one from
/etc/hosts or DHCP, or other config. If the
existing record is for an A or AAAA and
the record we're trying to insert is the same,
just drop the insert, but don't error the whole process. */
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
{
if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
return new;
#ifdef HAVE_IPV6
else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
return new;
#endif
}
insert_error = 1; insert_error = 1;
return NULL; return NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment