La Fonera's whitelist-patch dnsmasq
Posted by coldtobi | 31 Oct, 2007, 09:16Just 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:
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:
- [Updated] La Fonera: A bunch of Autoupdates (to 0.7.2.2)
- ReCaptcha Implementation finished
- Installing themes manually in firefox
- La Fonera: A better way to enable RedBoot via Telnet / Ethernet (safely) [HowTo]
- Installing Debian on the Thecus N2100 -- PART 2 -- Installing the Installer