« Previous | Next»

La Fonera's whitelist-patch dnsmasq

Posted by coldtobi | 31 Oct, 2007, 09:16

Just for the records:

In the La Fonera+ sources is the patch applied to dnsmasq. I did not anaylze it, but for the sake of completness, I am gonna place it here:

Anzeige
 

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 CNAMEn");
+                            }
+#endif
+                          }
+
               newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
               if (newc && cpp)
                 {

 (The patchfile can be downloaded here: 104-dnsmasq_whitelist.patch) The (almost) source is available here. (Almost, as they removed some files.)

La Fonera | Comments (0) | Trackbacks (0)

Related Articles:

0 Comments | "La Fonera's whitelist-patch dnsmasq" »

Add comment

 

 This is the ReCaptcha Plugin for Lifetype

Due to German legislation, all comments are moderated. If you get NO error message, your comment is accepted by the system and will be released at the earliest opportunity. Sorry for the inconvenience this might cause.

Inappropiate comments might be edited or not accepted.