import of dnsmasq-2.20.tar.gz
diff --git a/src/cache.c b/src/cache.c
index c50dbe7..b3e7d76 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -156,32 +156,52 @@
   return 1;
 }
 
-static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
+static int is_expired(time_t now, struct crec *crecp)
+{
+  if (crecp->flags & F_IMMORTAL)
+    return 0;
+
+  if (difftime(now, crecp->ttd) < 0)
+    return 0;
+
+  return 1;
+}
+
+static int 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
      entries but only in the same hash bucket as name.
      If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
      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
+     name exists in the cache as a HOSTS or DHCP entry (these are never deleted) */
   
-#define F_CACHESTATUS (F_HOSTS | F_DHCP | F_FORWARD | F_REVERSE | F_IPV4 | F_IPV6 | F_CNAME)
   struct crec *crecp, **up;
-  flags &= (F_FORWARD | F_REVERSE | F_IPV6 | F_IPV4 | F_CNAME);
 
   if (flags & F_FORWARD)
     {
       for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
-	if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
-	    is_outdated_cname_pointer(crecp) || 
-	    ((flags == (crecp->flags & F_CACHESTATUS)) && hostname_isequal(cache_get_name(crecp), name)))
-	  {
+	if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
+	  { 
 	    *up = crecp->hash_next;
 	    if (!(crecp->flags & (F_HOSTS | F_DHCP)))
-	      { 
+	      {
 		cache_unlink(crecp);
 		cache_free(crecp);
 	      }
+	  } 
+	else if ((crecp->flags & F_FORWARD) && 
+		 ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || (crecp->flags & F_CNAME)) &&
+		 hostname_isequal(cache_get_name(crecp), name))
+	  {
+	    if (crecp->flags & (F_HOSTS | F_DHCP))
+	      return 0;
+	    *up = crecp->hash_next;
+	    cache_unlink(crecp);
+	    cache_free(crecp);
 	  }
 	else
 	  up = &crecp->hash_next;
@@ -196,8 +216,7 @@
 #endif 
       for (i = 0; i < hash_size; i++)
 	for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
-	  if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
-	      ((flags == (crecp->flags & F_CACHESTATUS)) && memcmp(&crecp->addr.addr, addr, addrlen) == 0))
+	  if (is_expired(now, crecp))
 	    {
 	      *up = crecp->hash_next;
 	      if (!(crecp->flags & (F_HOSTS | F_DHCP)))
@@ -206,9 +225,20 @@
 		  cache_free(crecp);
 		}
 	    }
+	  else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
+		   (flags & crecp->flags & F_REVERSE) && 
+		   (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
+		   memcmp(&crecp->addr.addr, addr, addrlen) == 0)
+	    {
+	      *up = crecp->hash_next;
+	      cache_unlink(crecp);
+	      cache_free(crecp);
+	    }
 	  else
 	    up = &crecp->hash_next;
     }
+  
+  return 1;
 }
 
 /* Note: The normal calling sequence is
@@ -260,8 +290,13 @@
     return NULL;
 
   /* First remove any expired entries and entries for the name/address we
-     are currently inserting. */
-  cache_scan_free(name, addr, now, flags);
+     are currently inserting. Fail is we attempt to delete a name from
+     /etc/hosts or DHCP. */
+  if (!cache_scan_free(name, addr, now, flags))
+    {
+      insert_error = 1;
+      return NULL;
+    }
   
   /* Now get a cache entry from the end of the LRU list */
   while (1) {
@@ -376,8 +411,7 @@
 	{
 	  next = crecp->hash_next;
 	  
-	  if (!is_outdated_cname_pointer(crecp) &&
-	      ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0))
+	  if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
 	    {
 	      if ((crecp->flags & F_FORWARD) && 
 		  (crecp->flags & prot) &&
@@ -458,7 +492,7 @@
        
        for(i=0; i<hash_size; i++)
 	 for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
-	   if ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0)
+	   if (!is_expired(now, crecp))
 	     {      
 	       if ((crecp->flags & F_REVERSE) && 
 		   (crecp->flags & prot) &&
@@ -835,7 +869,15 @@
 	strcat(addrbuff, "-IPv6");
     }
   else if (flags & F_CNAME)
-    strcpy(addrbuff, "<CNAME>");
+    {
+      /* nasty abuse of IPV4 and IPV6 flags */
+      if (flags & F_IPV4)
+	strcpy(addrbuff, "<MX>");
+      else if (flags & F_IPV6)
+	strcpy(addrbuff, "<SRV>");
+      else
+	strcpy(addrbuff, "<CNAME>");
+    }
   else
 #ifdef HAVE_IPV6
     inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,