diff --git a/Makefile b/Makefile
-index 58a7975..616c6b7 100644
+index 2910320b6452..0a76ce3c5154 100644
--- a/Makefile
+++ b/Makefile
-@@ -69,7 +69,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
+@@ -73,7 +73,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
-- domain.o dnssec.o blockdata.o tables.o loop.o
-+ domain.o dnssec.o blockdata.o tables.o loop.o isc.o
+- domain.o dnssec.o blockdata.o tables.o loop.o inotify.o
++ domain.o dnssec.o blockdata.o tables.o loop.o inotify.o isc.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h
diff --git a/src/cache.c b/src/cache.c
-index 2c3a498..77a7046 100644
+index 117ae279fd4e..6ee7ee362e6c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -17,7 +17,7 @@
#ifdef HAVE_DNSSEC
cache_blockdata_free(crecp);
#endif
-@@ -1110,7 +1113,7 @@ void cache_reload(void)
- total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
+@@ -1151,7 +1154,7 @@ void cache_reload(void)
+
}
-#ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now)
{
struct crec *crecp = NULL;
-@@ -1188,7 +1191,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
+@@ -1229,7 +1232,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
addrlen = sizeof(struct in6_addr);
}
#endif
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
-@@ -1253,7 +1256,11 @@ void cache_add_dhcp_entry(char *host_name, int prot,
+@@ -1294,7 +1297,11 @@ void cache_add_dhcp_entry(char *host_name, int prot,
else
crec->ttd = ttd;
crec->addr.addr = *host_address;
cache_hash(crec);
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
-index f4a89fc..a448ec4 100644
+index e903a24c8105..eefc7f939933 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
-@@ -940,6 +940,11 @@ int main (int argc, char **argv)
+@@ -970,6 +970,11 @@ int main (int argc, char **argv)
poll_resolv(0, daemon->last_resolv != 0, now);
daemon->last_resolv = now;
+ load_dhcp(now);
+#endif
}
-
- if (FD_ISSET(piperead, &rset))
+ #endif
+
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
-index e74b15a..4a35168 100644
+index 89e758b56a0a..c5edd6fdf7f5 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
-@@ -1463,9 +1463,13 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
- void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
+@@ -1502,3 +1502,8 @@ void inotify_dnsmasq_init();
+ int inotify_check(time_t now);
+ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#endif
-
++
+/* isc.c */
+#ifdef HAVE_ISC_READER
+void load_dhcp(time_t now);
+#endif
-+
- /* loop.c */
- #ifdef HAVE_LOOP
- void loop_send_probes();
- int detect_loop(char *query, int type);
- #endif
--
diff --git a/src/isc.c b/src/isc.c
new file mode 100644
-index 0000000..5106442
+index 000000000000..51064426f17f
--- /dev/null
+++ b/src/isc.c
@@ -0,0 +1,251 @@
+
+#endif
diff --git a/src/option.c b/src/option.c
-index 45d8875..29c9ee5 100644
+index cb4e76ba0aa2..f6420fcbb7ab 100644
--- a/src/option.c
+++ b/src/option.c
-@@ -1669,7 +1669,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
+@@ -1693,7 +1693,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(_("bad MX target"));
break;
+++ /dev/null
-From 094b5c3d904bae9aeb3206d9f3b8348926b84975 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 21 Dec 2014 16:11:52 +0000
-Subject: [PATCH] Fix crash in DNSSEC code when attempting to verify large
- RRs.
-
----
- src/dnssec.c | 27 +++++++++++++++++++--------
- 1 files changed, 22 insertions(+), 8 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 69bfc29..3208ac7 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -456,16 +456,27 @@ static u16 *get_desc(int type)
-
- /* Return bytes of canonicalised rdata, when the return value is zero, the remaining
- data, pointed to by *p, should be used raw. */
--static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff,
-+static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
- unsigned char **p, u16 **desc)
- {
- int d = **desc;
-
-- (*desc)++;
--
- /* No more data needs mangling */
- if (d == (u16)-1)
-- return 0;
-+ {
-+ /* If there's more data than we have space for, just return what fits,
-+ we'll get called again for more chunks */
-+ if (end - *p > bufflen)
-+ {
-+ memcpy(buff, *p, bufflen);
-+ *p += bufflen;
-+ return bufflen;
-+ }
-+
-+ return 0;
-+ }
-+
-+ (*desc)++;
-
- if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
- /* domain-name, canonicalise */
-@@ -560,7 +571,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
- if (left1 != 0)
- memmove(buff1, buff1 + len1 - left1, left1);
-
-- if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
-+ if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
- {
- quit = 1;
- len1 = end1 - p1;
-@@ -571,7 +582,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
- if (left2 != 0)
- memmove(buff2, buff2 + len2 - left2, left2);
-
-- if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
-+ if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
- {
- quit = 1;
- len2 = end2 - p2;
-@@ -808,7 +819,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- /* canonicalise rdata and calculate length of same, use name buffer as workspace */
- cp = p;
- dp = rr_desc;
-- for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
-+ for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
- len += end - cp;
- len = htons(len);
- hash->update(ctx, 2, (unsigned char *)&len);
-@@ -816,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- /* Now canonicalise again and digest. */
- cp = p;
- dp = rr_desc;
-- while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
-+ while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
- hash->update(ctx, seg, (unsigned char *)name);
- if (cp != end)
- hash->update(ctx, end - cp, cp);
---
-1.7.10.4
-
+++ /dev/null
-From fbc5205702c7f6f431d9f1043c553d7fb62ddfdb Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 23 Dec 2014 15:46:08 +0000
-Subject: [PATCH] Fix problems validating NSEC3 and wildcards.
-
----
- src/dnssec.c | 253 +++++++++++++++++++++++++++++-----------------------------
- 1 file changed, 128 insertions(+), 125 deletions(-)
-
-diff --git a/src/dnssec.c b/src/dnssec.c
-index 3208ac7..9350d3e 100644
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -615,6 +615,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
- Return code:
- STAT_SECURE if it validates.
- STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
-+ (In this case *wildcard_out points to the "body" of the wildcard within name.)
- STAT_NO_SIG no RRsigs found.
- STAT_INSECURE RRset empty.
- STAT_BOGUS signature is wrong, bad packet.
-@@ -625,8 +626,8 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
-
- name is unchanged on exit. keyname is used as workspace and trashed.
- */
--static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
-- int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
-+static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type,
-+ char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
- {
- static unsigned char **rrset = NULL, **sigs = NULL;
- static int rrset_sz = 0, sig_sz = 0;
-@@ -798,8 +799,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
- {
- int k;
- for (k = name_labels - labels; k != 0; k--)
-- while (*name_start != '.' && *name_start != 0)
-- name_start++;
-+ {
-+ while (*name_start != '.' && *name_start != 0)
-+ name_start++;
-+ if (k != 1)
-+ name_start++;
-+ }
-+
-+ if (wildcard_out)
-+ *wildcard_out = name_start+1;
-+
- name_start--;
- *name_start = '*';
- }
-@@ -974,7 +983,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
- if (recp1->addr.ds.keylen == (int)hash->digest_size &&
- (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
- memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
-- validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
-+ validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
- {
- valid = 1;
- break;
-@@ -1443,11 +1452,88 @@ static int base32_decode(char *in, unsigned char *out)
- return p - out;
- }
-
-+static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
-+ char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count)
-+{
-+ int i, hash_len, salt_len, base32_len, rdlen;
-+ unsigned char *p, *psave;
-+
-+ for (i = 0; i < nsec_count; i++)
-+ if ((p = nsecs[i]))
-+ {
-+ if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
-+ !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
-+ return 0;
-+
-+ p += 8; /* class, type, TTL */
-+ GETSHORT(rdlen, p);
-+ psave = p;
-+ p += 4; /* algo, flags, iterations */
-+ salt_len = *p++; /* salt_len */
-+ p += salt_len; /* salt */
-+ hash_len = *p++; /* p now points to next hashed name */
-+
-+ if (!CHECK_LEN(header, p, plen, hash_len))
-+ return 0;
-+
-+ if (digest_len == base32_len && hash_len == base32_len)
-+ {
-+ int rc = memcmp(workspace2, digest, digest_len);
-+
-+ if (rc == 0)
-+ {
-+ /* We found an NSEC3 whose hashed name exactly matches the query, so
-+ we just need to check the type map. p points to the RR data for the record. */
-+
-+ int offset = (type & 0xff) >> 3;
-+ int mask = 0x80 >> (type & 0x07);
-+
-+ p += hash_len; /* skip next-domain hash */
-+ rdlen -= p - psave;
-+
-+ if (!CHECK_LEN(header, p, plen, rdlen))
-+ return 0;
-+
-+ while (rdlen >= 2)
-+ {
-+ if (p[0] == type >> 8)
-+ {
-+ /* Does the NSEC3 say our type exists? */
-+ if (offset < p[1] && (p[offset+2] & mask) != 0)
-+ return STAT_BOGUS;
-+
-+ break; /* finshed checking */
-+ }
-+
-+ rdlen -= p[1];
-+ p += p[1];
-+ }
-+
-+ return 1;
-+ }
-+ else if (rc <= 0)
-+ {
-+ /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
-+ wrap around case, name-hash falls between NSEC3 name-hash and end */
-+ if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
-+ return 1;
-+ }
-+ else
-+ {
-+ /* wrap around case, name falls between start and next domain name */
-+ if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
-+ return 1;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
- static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
-- char *workspace1, char *workspace2, char *name, int type)
-+ char *workspace1, char *workspace2, char *name, int type, char *wildname)
- {
- unsigned char *salt, *p, *digest;
-- int digest_len, i, iterations, salt_len, hash_len, base32_len, algo = 0;
-+ int digest_len, i, iterations, salt_len, base32_len, algo = 0;
- struct nettle_hash const *hash;
- char *closest_encloser, *next_closest, *wildcard;
-
-@@ -1520,7 +1606,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- if (!(hash = hash_find("sha1")))
- return STAT_BOGUS;
-
-- /* Now, we need the "closest encloser NSEC3" */
-+ if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
-+ return STAT_BOGUS;
-+
-+ if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
-+ return STAT_SECURE;
-+
-+ /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
-+ or an answer inferred from a wildcard record. */
- closest_encloser = name;
- next_closest = NULL;
-
-@@ -1529,6 +1622,9 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- if (*closest_encloser == '.')
- closest_encloser++;
-
-+ if (wildname && hostname_isequal(closest_encloser, wildname))
-+ break;
-+
- if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
- return STAT_BOGUS;
-
-@@ -1551,127 +1647,33 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
- }
- while ((closest_encloser = strchr(closest_encloser, '.')));
-
-- /* No usable NSEC3s */
-- if (i == nsec_count)
-+ if (!closest_encloser)
- return STAT_BOGUS;
-
-- if (!next_closest)
-- {
-- /* We found an NSEC3 whose hashed name exactly matches the query, so
-- Now we just need to check the type map. p points to the RR data for the record. */
-- int rdlen;
-- unsigned char *psave;
-- int offset = (type & 0xff) >> 3;
-- int mask = 0x80 >> (type & 0x07);
--
-- p += 8; /* class, type, TTL */
-- GETSHORT(rdlen, p);
-- psave = p;
-- p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
-- hash_len = *p++;
-- if (!CHECK_LEN(header, p, plen, hash_len))
-- return STAT_BOGUS; /* bad packet */
-- p += hash_len;
-- rdlen -= p - psave;
--
-- while (rdlen >= 2)
-- {
-- if (!CHECK_LEN(header, p, plen, rdlen))
-- return STAT_BOGUS;
--
-- if (p[0] == type >> 8)
-- {
-- /* Does the NSEC3 say our type exists? */
-- if (offset < p[1] && (p[offset+2] & mask) != 0)
-- return STAT_BOGUS;
--
-- break; /* finshed checking */
-- }
--
-- rdlen -= p[1];
-- p += p[1];
-- }
--
-- return STAT_SECURE;
-- }
--
- /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
- if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
- return STAT_BOGUS;
-
-- for (i = 0; i < nsec_count; i++)
-- if ((p = nsecs[i]))
-- {
-- if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
-- !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
-- return STAT_BOGUS;
--
-- p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
-- hash_len = *p++; /* p now points to next hashed name */
--
-- if (!CHECK_LEN(header, p, plen, hash_len))
-- return STAT_BOGUS;
--
-- if (digest_len == base32_len && hash_len == base32_len)
-- {
-- if (memcmp(workspace2, digest, digest_len) <= 0)
-- {
-- /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
-- wrap around case, name-hash falls between NSEC3 name-hash and end */
-- if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
-- return STAT_SECURE;
-- }
-- else
-- {
-- /* wrap around case, name falls between start and next domain name */
-- if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
-- return STAT_SECURE;
-- }
-- }
-- }
--
-- /* Finally, check that there's no seat of wildcard synthesis */
-- if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
-- return STAT_BOGUS;
--
-- wildcard--;
-- *wildcard = '*';
--
-- if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
-+ if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
- return STAT_BOGUS;
-
-- for (i = 0; i < nsec_count; i++)
-- if ((p = nsecs[i]))
-- {
-- if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
-- !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
-- return STAT_BOGUS;
--
-- p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
-- hash_len = *p++; /* p now points to next hashed name */
--
-- if (!CHECK_LEN(header, p, plen, hash_len))
-- return STAT_BOGUS;
--
-- if (digest_len == base32_len && hash_len == base32_len)
-- {
-- if (memcmp(workspace2, digest, digest_len) <= 0)
-- {
-- /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
-- wrap around case, name-hash falls between NSEC3 name-hash and end */
-- if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
-- return STAT_SECURE;
-- }
-- else
-- {
-- /* wrap around case, name falls between start and next domain name */
-- if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
-- return STAT_SECURE;
-- }
-- }
-- }
-+ /* Finally, check that there's no seat of wildcard synthesis */
-+ if (!wildname)
-+ {
-+ if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
-+ return STAT_BOGUS;
-+
-+ wildcard--;
-+ *wildcard = '*';
-+
-+ if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
-+ return STAT_BOGUS;
-+
-+ if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
-+ return STAT_BOGUS;
-+ }
-
-- return STAT_BOGUS;
-+ return STAT_SECURE;
- }
-
- /* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
-@@ -1792,8 +1794,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- struct all_addr a;
- struct blockdata *key;
- struct crec *crecp;
--
-- rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0);
-+ char *wildname;
-+
-+ rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
-
- if (rc == STAT_SECURE_WILDCARD)
- {
-@@ -1807,7 +1810,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- if (nsec_type == T_NSEC)
- rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
- else
-- rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
-+ rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, wildname);
-
- if (rc != STAT_SECURE)
- return rc;
-@@ -1933,7 +1936,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
- if (nsec_type == T_NSEC)
- return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
- else
-- return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
-+ return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL);
- }
-
- /* Chase the CNAME chain in the packet until the first record which _doesn't validate.
-@@ -1980,7 +1983,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
- return STAT_INSECURE;
-
- /* validate CNAME chain, return if insecure or need more data */
-- rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, 0, 0, 0);
-+ rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
- if (rc != STAT_SECURE)
- {
- if (rc == STAT_NO_SIG)
---
-1.7.10.4
-
+++ /dev/null
-From cbc652423403e3cef00e00240f6beef713142246 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 21 Dec 2014 21:21:53 +0000
-Subject: [PATCH] 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.
----
- src/cache.c | 34 +++++++++++++++++++++++++---------
- 1 file changed, 25 insertions(+), 9 deletions(-)
-
-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 @@ static int is_expired(time_t now, struct crec *crecp)
- 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 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
- 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 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
- (((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 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
- 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 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
- up = &crecp->hash_next;
- }
-
-- return 1;
-+ return NULL;
- }
-
- /* Note: The normal calling sequence is
-@@ -471,10 +471,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
- 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;
- }
---
-1.7.10.4
-