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.
diff --git a/src/cache.c b/src/cache.c
index f9e1d31..ff1ca6f 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -322,7 +322,7 @@
   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.
      If (flags & F_FORWARD) then remove any forward entries for name and any expired
@@ -331,8 +331,8 @@
      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
-     name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
+     In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
+     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>
      so that when we hit an entry which isn't reverse and is immortal, we're done. */
@@ -361,7 +361,7 @@
 		  (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
 		{
 		  if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
-		    return 0;
+		    return crecp;
 		  *up = crecp->hash_next;
 		  cache_unlink(crecp);
 		  cache_free(crecp);
@@ -378,7 +378,7 @@
 		   crecp->addr.sig.type_covered == addr->addr.dnssec.type))
 		{
 		  if (crecp->flags & F_CONFIG)
-		    return 0;
+		    return crecp;
 		  *up = crecp->hash_next;
 		  cache_unlink(crecp);
 		  cache_free(crecp);
@@ -423,7 +423,7 @@
 	    up = &crecp->hash_next;
     }
   
-  return 1;
+  return NULL;
 }
 
 /* Note: The normal calling sequence is
@@ -471,10 +471,26 @@
     return NULL;
   
   /* First remove any expired entries and entries for the name/address we
-     are currently inserting. Fail if we attempt to delete a name from
-     /etc/hosts or DHCP. */
-  if (!cache_scan_free(name, addr, now, flags))
+     are currently inserting. */
+  if ((new = 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;
       return NULL;
     }