# HG changeset patch
# Parent 847c22ddbdd92b4a49325912c5bb7c075b0350e3
dnscache CNAME handling
diff -r 847c22ddbdd9 source/dietlibc/diet-djbdns/FrugalBuild
--- a/source/dietlibc/diet-djbdns/FrugalBuild Fri Feb 17 10:25:48 2012 +0100
+++ b/source/dietlibc/diet-djbdns/FrugalBuild Fri Feb 17 10:48:29 2012 +0100
@@ -4,7 +4,7 @@
pkgorig=djbdns
pkgname=$branch-$pkgorig
pkgver=1.05
-pkgrel=3
+pkgrel=4
pkgdesc="High-performant & secure DNS services."
url="http://cr.yp.to/djbdns.html"
archs=(i686)
@@ -13,12 +13,15 @@
makedepends=(dietlibc)
install="$pkgorig.install"
backup=(etc/dnsroots.global)
-source=(http://cr.yp.to/$pkgorig/$pkgorig-$pkgver.tar.gz)
-sha1sums=('2efdb3a039d0c548f40936aa9cb30829e0ce8c3d')
+source=(http://cr.yp.to/$pkgorig/$pkgorig-$pkgver.tar.gz \
+ dnscache-cname-handling.patch)
+sha1sums=('2efdb3a039d0c548f40936aa9cb30829e0ce8c3d' \
+ 'bbfa9b12aa298268a8da07ef6de279883c15893e')
provides=(djbdns)
build() {
Fcd $pkgorig-$pkgver
+ Fpatchall
echo "diet gcc ${CFLAGS}" > conf-cc
echo "diet gcc -s -static" > conf-ld
echo "/usr" > conf-home
diff -r 847c22ddbdd9 source/dietlibc/diet-djbdns/dnscache-cname-handling.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/dietlibc/diet-djbdns/dnscache-cname-handling.patch Fri Feb 17 10:48:29 2012 +0100
@@ -0,0 +1,256 @@
+http://homepage.ntlworld.com/jonathan.deboynepollard/Softwares/djbdns/dnscache-cname-handling.patch
+http://homepage.ntlworld.com/jonathan.deboynepollard/Softwares/djbdns/
+
+Making dnscache handle client-side aliases ("CNAME" records) correctly
+
+There are several problems with the way that dnscache handles client-side
+aliases, that become acutely apparent if one patches qmail to remove the
+workaround for a BIND version 4 problem. This patch modifies the behaviour of
+dnscache, to correct them, in the following ways:
+
+dnscache will cache "CNAME" resource record sets (both empty and non-empty).
+
+dnscache will correctly ignore a cached "CNAME" resource record set that
+happens to be empty (which will result if an explicit "CNAME" query is made
+against a domain name that has no client-side aliases).
+
+dnscache will notice lame servers where the lame delegation is present at the
+end of a chain of client-side aliases. Any instances of tinydns that have not
+been patched to make them publish whole alias chains instead of just the first
+links will thus be logged as "lame".
+
+dnscache will not issue redundant queries if it can follow an entire
+client-side alias chain to the end using the information that it already has in
+a response.
+
+dnscache will cache any in-bailiwick information that it receives from lame
+servers. Any in-bailiwick client-side alias information and delegation
+information that are received from an otherwise "lame" server will no longer be
+thrown away along with the bath-water.
+
+--- djbdns-1.05-original/query.c Sun Feb 11 21:11:45 2001
++++ djbdns-1.05/query.c Wed Mar 26 15:48:20 2003
+@@ -91,6 +91,21 @@
+ }
+ }
+
++static int move_name_to_alias(struct query *z,uint32 ttl)
++{
++ int j ;
++
++ if (z->alias[QUERY_MAXALIAS - 1]) return 0 ;
++ for (j = QUERY_MAXALIAS - 1;j > 0;--j)
++ z->alias[j] = z->alias[j - 1];
++ for (j = QUERY_MAXALIAS - 1;j > 0;--j)
++ z->aliasttl[j] = z->aliasttl[j - 1];
++ z->alias[0] = z->name[0];
++ z->aliasttl[0] = ttl;
++ z->name[0] = 0;
++ return 1 ;
++}
++
+ static int rqa(struct query *z)
+ {
+ int i;
+@@ -123,7 +138,6 @@
+ static char *t1 = 0;
+ static char *t2 = 0;
+ static char *t3 = 0;
+-static char *cname = 0;
+ static char *referral = 0;
+ static unsigned int *records = 0;
+
+@@ -179,15 +193,14 @@
+ uint16 datalen;
+ char *control;
+ char *d;
++ char *owner_name = 0 ;
+ const char *dtype;
+ unsigned int dlen;
+ int flagout;
+- int flagcname;
+ int flagreferral;
+ int flagsoa;
+ uint32 ttl;
+ uint32 soattl;
+- uint32 cnamettl;
+ int i;
+ int j;
+ int k;
+@@ -252,7 +265,10 @@
+
+ byte_copy(key,2,DNS_T_CNAME);
+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+- if (cached) {
++ /* A previous explicit query might have caused an empty RRSet to have been
++ ** cached. Take care to ignore such a thing.
++ */
++ if (cached && cachedlen) {
+ if (typematch(DNS_T_CNAME,dtype)) {
+ log_cachedanswer(d,DNS_T_CNAME);
+ if (!rqa(z)) goto DIE;
+@@ -261,8 +277,11 @@
+ return 1;
+ }
+ log_cachedcname(d,cached);
+- if (!dns_domain_copy(&cname,cached)) goto DIE;
+- goto CNAME;
++ if (!z->level) {
++ if (!move_name_to_alias(z,ttl)) goto DIE ;
++ }
++ if (!dns_domain_copy(&z->name[z->level],cached)) goto DIE;
++ goto NEWNAME;
+ }
+
+ if (typematch(DNS_T_NS,dtype)) {
+@@ -351,7 +370,7 @@
+ }
+ }
+
+- if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
++ if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
+ byte_copy(key,2,dtype);
+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+ if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
+@@ -471,29 +490,31 @@
+ if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */
+
+ flagout = 0;
+- flagcname = 0;
+ flagreferral = 0;
+ flagsoa = 0;
+ soattl = 0;
+- cnamettl = 0;
++ if (!dns_domain_copy(&owner_name,d)) goto DIE;
++ /* This code assumes that the CNAME chain is presented in the correct
++ ** order. The example algorithm in RFC 1034 will actually result in this
++ ** being the case, but the words do not require it to be so.
++ */
+ for (j = 0;j < numanswers;++j) {
+ pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
+ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
+
+- if (dns_domain_equal(t1,d))
++ if (dns_domain_equal(t1,owner_name))
+ if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */
+ if (typematch(header,dtype))
+ flagout = 1;
+ else if (typematch(header,DNS_T_CNAME)) {
+- if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE;
+- flagcname = 1;
+- cnamettl = ttlget(header + 4);
++ if (!dns_packet_getname(buf,len,pos,&owner_name)) goto DIE;
+ }
+ }
+
+ uint16_unpack_big(header + 8,&datalen);
+ pos += datalen;
+ }
++ dns_domain_free(&owner_name) ;
+ posauthority = pos;
+
+ for (j = 0;j < numauthority;++j) {
+@@ -515,15 +536,6 @@
+ }
+ posglue = pos;
+
+-
+- if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
+- if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
+- log_lame(whichserver,control,referral);
+- byte_zero(whichserver,4);
+- goto HAVENS;
+- }
+-
+-
+ if (records) { alloc_free(records); records = 0; }
+
+ k = numanswers + numauthority + numglue;
+@@ -670,24 +682,36 @@
+
+ alloc_free(records); records = 0;
+
++ if (byte_diff(DNS_T_CNAME,2,dtype)) {
++ /* This code assumes that the CNAME chain is presented in the correct
++ ** order. The example algorithm in RFC 1034 will actually result in this
++ ** being the case, but the words do not require it to be so.
++ */
++ pos = posanswers;
++ for (j = 0;j < numanswers;++j) {
++ pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
++ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
++
++ if (dns_domain_equal(t1,d))
++ if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */
++ if (typematch(header,DNS_T_CNAME)) {
++ ttl = ttlget(header + 4);
++ if (z->level == 0) {
++ if (!move_name_to_alias(z,ttl)) goto DIE ;
++ }
++ if (!dns_packet_getname(buf,len,pos,&z->name[z->level])) goto DIE;
++ d = z->name[z->level];
++ if (!dns_domain_suffix(d,control) || !roots_same(d,control))
++ goto NEWNAME ; /* Cannot trust the chain further - restart using current name */
++ }
++ }
+
+- if (flagcname) {
+- ttl = cnamettl;
+- CNAME:
+- if (!z->level) {
+- if (z->alias[QUERY_MAXALIAS - 1]) goto DIE;
+- for (j = QUERY_MAXALIAS - 1;j > 0;--j)
+- z->alias[j] = z->alias[j - 1];
+- for (j = QUERY_MAXALIAS - 1;j > 0;--j)
+- z->aliasttl[j] = z->aliasttl[j - 1];
+- z->alias[0] = z->name[0];
+- z->aliasttl[0] = ttl;
+- z->name[0] = 0;
++ uint16_unpack_big(header + 8,&datalen);
++ pos += datalen;
+ }
+- if (!dns_domain_copy(&z->name[z->level],cname)) goto DIE;
+- goto NEWNAME;
+ }
+
++ /* A "no such name" error applies to the end of any CNAME chain, not to the start. */
+ if (rcode == 3) {
+ log_nxdomain(whichserver,d,soattl);
+ cachegeneric(DNS_T_ANY,d,"",0,soattl);
+@@ -700,10 +724,26 @@
+ return 1;
+ }
+
++ /* We check for a lame server _after_ we have cached any records that it
++ ** might have returned to us. This copes better with the incorrect
++ ** behaviour of one content DNS server software that doesn't return
++ ** complete CNAME chains but instead returns only the first link in a
++ ** chain followed by a lame delegation to the same server.
++ ** Also: We check for a lame server _after_ following the CNAME chain. The
++ ** delegation in a referral answer applies to the _end_ of the chain, not
++ ** to the beginning.
++ */
++ if (!rcode && !flagout && flagreferral && !flagsoa)
++ if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
++ log_lame(whichserver,control,referral);
++ byte_zero(whichserver,4);
++ goto HAVENS;
++ }
++
+ if (!flagout && flagsoa)
++ /* Don't save empty RRSets for those types that we use as special markers. */
+ if (byte_diff(DNS_T_ANY,2,dtype))
+- if (byte_diff(DNS_T_AXFR,2,dtype))
+- if (byte_diff(DNS_T_CNAME,2,dtype)) {
++ if (byte_diff(DNS_T_AXFR,2,dtype)) {
+ save_start();
+ save_finish(dtype,d,soattl);
+ log_nodata(whichserver,d,dtype,soattl);
+@@ -815,6 +855,7 @@
+ DIE:
+ cleanup(z);
+ if (records) { alloc_free(records); records = 0; }
++ dns_domain_free(&owner_name) ;
+ return -1;
+ }
+