diff -uprN -X /tmp/dontdiff dnsmasq-2.38/src/cache.c dnsmasq-2.38-whitelist/src/cache.c
--- dnsmasq-2.38/src/cache.c	2007-07-11 18:18:46.000000000 +0200
+++ dnsmasq-2.38-whitelist/src/cache.c	2007-07-06 11:16:06.000000000 +0200
@@ -20,6 +20,11 @@ static int bignames_left, log_queries, c
 static int uid;
 static char *addrbuff;
 
+#ifdef HAVE_WHITELIST
+static char *whitelist_file;
+static int maxregnum = 255;
+#endif
+
 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
 static const struct {
   unsigned int type;
@@ -377,6 +382,11 @@ struct crec *cache_insert(char *name, st
   union bigname *big_name = NULL;
   int freed_all = flags & F_REVERSE;
 
+#ifdef HAVE_WHITELIST
+  if (whitelist_file)
+    whitelist_cache_insert(flags | F_UPSTREAM, name, addr);
+#endif
+
   log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
 
   /* name is needed as workspace by log_query in this case */
@@ -1069,3 +1079,197 @@ void log_query(unsigned short flags, cha
     syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name);
 }
 
+#ifdef HAVE_WHITELIST
+/* whitelist stuff */
+
+int check_whitelist_file(const char *file)
+{
+  struct stat buf_stat;
+
+  if (stat(file, &buf_stat) < 0)
+    return 1;
+
+  whitelist_file = strdup(file);
+
+  return 0;
+}
+
+void whitelist_cache_insert(unsigned short flags, char *name, struct all_addr *addr)
+{
+  int ret;
+  char addrbuffer[ADDRSTRLEN];
+
+  if ((flags & F_FORWARD) &&
+                  (flags & F_UPSTREAM) &&
+                  (!(flags & F_CNAME)) &&
+                  (!(flags & F_NEG)) &&
+                  (addr != NULL)) {
+
+
+    ret = domain_in_whitelist(name);
+
+   switch (ret)
+   {
+      case 1:
+#ifdef HAVE_IPV6
+        inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
+                    addr, addrbuffer, ADDRSTRLEN);
+        syslog(LOG_INFO, "JAVI ip cached: %s", addrbuffer);
+#else
+        syslog(LOG_INFO, "JAVI ip cached: %s", inet_ntoa(addr->addr.addr4));
+#endif
+        commit_whitelist_cache(addr);
+        break;
+      case 2:
+#ifdef HAVE_IPV6
+        inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
+                    addr, addrbuffer, ADDRSTRLEN);
+        syslog(LOG_INFO, "JAVI ip dropped: %s", addrbuffer);
+#else
+        syslog(LOG_INFO, "JAVI ip dropped: %s", inet_ntoa(addr->addr.addr4));
+#endif
+        dropip_from_cache(addr);
+        break;
+    }
+  }
+
+  return;
+}
+
+int domain_in_whitelist(char *name)
+{
+  FILE *fp;
+  char *line = NULL;
+  size_t len = 0;
+  char *p;
+
+  if ((fp = fopen(whitelist_file, "r")) == NULL) {
+    syslog(LOG_DEBUG, "error open: %s", whitelist_file);
+    return -1;
+  }
+
+  /*syslog(LOG_DEBUG, "open: %s", whitelist_file);*/
+
+  while (getline(&line, &len, fp) != -1) {
+    p = strtok(line, "\n");
+
+    if ((*p == '!') && !fnmatch(p+1, name, FNM_NOESCAPE)) {
+      syslog(LOG_DEBUG, "%s matches %s", name, p);
+      free(line);
+      fclose(fp);
+      return 2;
+    }
+  }
+
+  rewind(fp);
+
+  while (getline(&line, &len, fp) != -1) {
+    p = strtok(line, "\n");
+    /*syslog(LOG_DEBUG, "try %s whith %s (in file)", name, p);*/
+    if (!fnmatch(p, name, FNM_NOESCAPE)) {
+      /*syslog(LOG_DEBUG, "%s matches %s", name, p);*/
+      free(line);
+      fclose(fp);
+      return 1;
+    }
+  }
+
+  if (line)
+    free(line);
+
+  fclose(fp);
+
+  /*syslog(LOG_DEBUG, "NO matches %s", name);*/
+
+  return 0;
+}
+
+int commit_whitelist_cache(struct all_addr *addr)
+{
+  struct in_addr inp;
+  struct in_addr tmp_inp;
+  static FILE *fp = NULL;
+  long pos;
+
+  if (fp == NULL)
+    if ((fp = fopen("/tmp/whitelist.cache", "w+")) == NULL) {
+      syslog(LOG_DEBUG, "error open: /etc/config/whitelist.cache, %d", errno);
+      return -1;
+    }
+
+#ifdef HAVE_IPV6
+  memcpy(&inp, &addr->addr.addr4, sizeof(struct in_addr));
+#endif
+
+  /*
+   * look for duplicates.
+   */
+  pos = ftell(fp);
+  rewind(fp);
+
+  while (fread(&tmp_inp, sizeof(struct in_addr), 1, fp) == 1) {
+    if (tmp_inp.s_addr == inp.s_addr) {
+      syslog(LOG_DEBUG, "colission!\n");
+      fseek(fp, pos, SEEK_SET);
+      return 0;
+    }
+  }
+
+  if (maxregnum == (pos / sizeof(struct in_addr))) {
+    syslog(LOG_DEBUG, "rewind whitelist cache: reached %d records!\n", maxregnum);
+    rewind(fp);
+  }
+  else 
+    fseek(fp, pos, SEEK_SET);
+  
+  fwrite(&inp, sizeof(struct in_addr), 1, fp);
+
+  fflush(fp);
+
+  /*syslog(LOG_DEBUG, "whitelist.cache commited!\n");*/
+
+  return 0;
+}
+
+int dropip_from_cache(struct all_addr *addr)
+{
+  struct in_addr inp;
+  struct in_addr tmp_inp;
+  static FILE *fp = NULL;
+  struct crec *crec;
+
+  if ((fp = fopen("/tmp/whitelist.cache", "r+")) == NULL) {
+      syslog(LOG_DEBUG, "error open: /etc/config/whitelist.cache, %d", errno);
+      return -1;
+   }
+
+#ifdef HAVE_IPV6
+  memcpy(&inp, &addr->addr.addr4, sizeof(struct in_addr));
+#endif
+  
+  while (fread(&tmp_inp, sizeof(struct in_addr), 1, fp) == 1) {
+    if (tmp_inp.s_addr == inp.s_addr) {
+      syslog(LOG_DEBUG, "replaced!\n");
+      fseek(fp, ftell(fp) - sizeof(struct in_addr), SEEK_SET);
+      inet_aton("127.0.0.1", &tmp_inp);
+      fwrite(&tmp_inp, sizeof(struct in_addr), 1, fp);
+      fflush(fp);
+      fclose(fp);
+      kill(getpid(), SIGHUP);
+/*
+      if ((crec = cache_find_by_addr(NULL, addr, 0, 0))) {
+      	syslog(LOG_DEBUG, "pasado");
+      	syslog(LOG_DEBUG, "%s", crec->name.namep);
+      }
+      syslog(LOG_DEBUG, "cache_get_name: %s", cache_get_name(crec));
+*/
+      return 0;
+    }
+  }
+
+
+  fclose(fp);
+
+  return -1;
+}
+#endif
diff -uprN -X /tmp/dontdiff dnsmasq-2.38/src/dnsmasq.c dnsmasq-2.38-whitelist/src/dnsmasq.c
--- dnsmasq-2.38/src/dnsmasq.c	2007-02-06 23:09:40.000000000 +0100
+++ dnsmasq-2.38-whitelist/src/dnsmasq.c	2007-07-06 11:16:06.000000000 +0200
@@ -440,6 +440,16 @@ int main (int argc, char **argv)
 	}
       syslog(LOG_WARNING, _("running as root"));
     }
+
+#ifdef HAVE_WHITELIST
+  if (daemon->whitelist_file)
+    if (check_whitelist_file(daemon->whitelist_file)) {
+      syslog(LOG_INFO, "ERROR: unable access whitelist file: %s",
+                        daemon->whitelist_file);
+      daemon->whitelist_file = NULL;
+     } else
+       syslog(LOG_INFO, "whitelist file: %s", daemon->whitelist_file);
+#endif
   
   check_servers(daemon);
 
diff -uprN -X /tmp/dontdiff dnsmasq-2.38/src/dnsmasq.h dnsmasq-2.38-whitelist/src/dnsmasq.h
--- dnsmasq-2.38/src/dnsmasq.h	2007-02-11 13:46:04.000000000 +0100
+++ dnsmasq-2.38-whitelist/src/dnsmasq.h	2007-07-06 11:16:06.000000000 +0200
@@ -13,6 +13,7 @@
 #define COPYRIGHT "Copyright (C) 2000-2007 Simon Kelley" 
 
 /* get these before config.h  for IPv6 stuff... */
+#define _GNU_SOURCE
 #include <sys/types.h> 
 #include <netinet/in.h>
 
@@ -81,6 +82,8 @@ extern int capset(cap_user_header_t head
 #include <sys/prctl.h>
 #endif
 
+#include <fnmatch.h>
+
 /* Min buffer size: we check after adding each record, so there must be 
    memory for the largest packet, and the largest record so the
    min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
@@ -524,6 +527,11 @@ struct daemon {
   /* TFTP stuff */
   struct tftp_transfer *tftp_trans;
   char *tftp_prefix; 
+
+#ifdef HAVE_WHITELIST
+  /* whitelist stuff */
+  char *whitelist_file;
+#endif
 };
 
 /* cache.c */
@@ -544,6 +552,15 @@ void cache_add_dhcp_entry(struct daemon 
 void cache_unhash_dhcp(void);
 void dump_cache(struct daemon *daemon, time_t now);
 char *cache_get_name(struct crec *crecp);
+#ifdef HAVE_WHITELIST
+ /* whitelist stuff */
+int check_whitelist_file(const char *file);
+void whitelist_cache_insert(unsigned short flags, char *name, struct all_addr *addr);
+int domain_in_whitelist(char *name);
+int commit_whitelist_cache(struct all_addr *addr);
+int dropip_from_cache(struct all_addr *addr);
+#endif
+
 
 /* rfc1035.c */
 unsigned short extract_request(HEADER *header, size_t qlen, 
diff -uprN -X /tmp/dontdiff dnsmasq-2.38/src/option.c dnsmasq-2.38-whitelist/src/option.c
--- dnsmasq-2.38/src/option.c	2007-02-11 13:43:58.000000000 +0100
+++ dnsmasq-2.38-whitelist/src/option.c	2007-07-06 11:16:06.000000000 +0200
@@ -15,6 +15,9 @@
 
 #include "dnsmasq.h"
 
+/* FIXME: hardcode option */
+int have_whitelist = 1;
+
 #ifndef HAVE_GETOPT_LONG
 struct myoption {
   const char *name;
@@ -1994,6 +1997,9 @@ struct daemon *read_opts(int argc, char 
   daemon->tftp_max = TFTP_MAX_CONNECTIONS;
   daemon->edns_pktsz = EDNS_PKTSZ;
   daemon->log_fac = -1;
+#ifdef HAVE_WHITELIST
+  daemon->whitelist_file = "/etc/config/whitelist.dnsmasq";
+#endif
   add_txt(daemon, "version.bind", "dnsmasq-" VERSION );
   add_txt(daemon, "authors.bind", "Simon Kelley");
   add_txt(daemon, "copyright.bind", COPYRIGHT);
diff -uprN -X /tmp/dontdiff dnsmasq-2.38/src/rfc1035.c dnsmasq-2.38-whitelist/src/rfc1035.c
--- dnsmasq-2.38/src/rfc1035.c	2007-02-06 23:09:40.000000000 +0100
+++ dnsmasq-2.38-whitelist/src/rfc1035.c	2007-07-11 18:18:16.000000000 +0200
@@ -695,7 +695,15 @@ void extract_addresses(HEADER *header, s
 	    continue;
 	    
 	  if (!(flags & F_NXDOMAIN))
-	    {
+	  {
+#ifdef HAVE_WHITELIST
+            char *alias = NULL;
+            char *cannonical_name = NULL;
+            int ret;
+            int in_loop;
+
+            in_loop = 0;
+#endif
 	    cname_loop1:
 	      if (!(p1 = skip_questions(header, qlen)))
 		return;
@@ -717,6 +725,9 @@ void extract_addresses(HEADER *header, s
 			{
 			  if (!cname_count--)
 			    return; /* looped CNAMES */
+#ifdef HAVE_WHITELIST
+                          alias = strdup(name);
+#endif
 			  newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
 			  if (newc && cpp)
 			    {
@@ -730,13 +741,48 @@ void extract_addresses(HEADER *header, s
 			  
 			  if (!extract_name(header, qlen, &p1, name, 1))
 			    return;
-			  goto cname_loop1;
-			}
-		      else
-			{
-			  found = 1;
-			  if (aqtype == T_A)
-			    dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
+#ifdef HAVE_WHITELIST
+                          ret = domain_in_whitelist(alias);
+
+                          switch (ret)
+                          {
+                            case 1:
+                              syslog(LOG_INFO, "%s es un ALIAS en la whitelist (cannonical: %s)", alias, name);
+                              free(alias);
+                              cannonical_name = strdup(name);
+                              in_loop = 1;
+                              break;
+                            case 2:
+                              syslog(LOG_INFO, "%s es un ALIAS en la whitelist (cannonical: %s)", alias, name);
+                              free(alias);
+                              cannonical_name = NULL;
+                              break;
+                          }
+#endif
+                          goto cname_loop1;
+                        }
+                      else
+                      {
+                         found = 1;
+                         if (aqtype == T_A) {
+                           dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
+#ifdef HAVE_WHITELIST
+                           if ((cannonical_name != NULL) && !strcmp(name, cannonical_name)) {
+                             syslog(LOG_INFO, "%s match %s ip iserted in whitelist", name, cannonical_name);
+                             free(cannonical_name);
+                             cannonical_name = NULL;
+                             in_loop = 0;
+                             commit_whitelist_cache((struct all_addr *)p1);
+                            }
+
+                            if (in_loop) {
+                             commit_whitelist_cache((struct all_addr *)p1);
+                             in_loop = 0;
+                             syslog(LOG_INFO, "doble CNAME\n");
+                            }
+#endif
+                          }
+
 			  newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
 			  if (newc && cpp)
 			    {

