339c8fafe7d17d72fab971ca8603f156937f7c71
[openwrt/svn-archive/archive.git] / net / djbdns / patches / 200-dnscache-cname-handling.patch
1 --- djbdns-1.05-original/query.c Sun Feb 11 21:11:45 2001
2 +++ djbdns-1.05/query.c Wed Mar 26 15:48:20 2003
3 @@ -91,6 +91,21 @@
4 }
5 }
6
7 +static int move_name_to_alias(struct query *z,uint32 ttl)
8 +{
9 + int j ;
10 +
11 + if (z->alias[QUERY_MAXALIAS - 1]) return 0 ;
12 + for (j = QUERY_MAXALIAS - 1;j > 0;--j)
13 + z->alias[j] = z->alias[j - 1];
14 + for (j = QUERY_MAXALIAS - 1;j > 0;--j)
15 + z->aliasttl[j] = z->aliasttl[j - 1];
16 + z->alias[0] = z->name[0];
17 + z->aliasttl[0] = ttl;
18 + z->name[0] = 0;
19 + return 1 ;
20 +}
21 +
22 static int rqa(struct query *z)
23 {
24 int i;
25 @@ -123,7 +138,6 @@
26 static char *t1 = 0;
27 static char *t2 = 0;
28 static char *t3 = 0;
29 -static char *cname = 0;
30 static char *referral = 0;
31 static unsigned int *records = 0;
32
33 @@ -179,15 +193,14 @@
34 uint16 datalen;
35 char *control;
36 char *d;
37 + char *owner_name = 0 ;
38 const char *dtype;
39 unsigned int dlen;
40 int flagout;
41 - int flagcname;
42 int flagreferral;
43 int flagsoa;
44 uint32 ttl;
45 uint32 soattl;
46 - uint32 cnamettl;
47 int i;
48 int j;
49 int k;
50 @@ -252,7 +265,10 @@
51
52 byte_copy(key,2,DNS_T_CNAME);
53 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
54 - if (cached) {
55 + /* A previous explicit query might have caused an empty RRSet to have been
56 + ** cached. Take care to ignore such a thing.
57 + */
58 + if (cached && cachedlen) {
59 if (typematch(DNS_T_CNAME,dtype)) {
60 log_cachedanswer(d,DNS_T_CNAME);
61 if (!rqa(z)) goto DIE;
62 @@ -261,8 +277,11 @@
63 return 1;
64 }
65 log_cachedcname(d,cached);
66 - if (!dns_domain_copy(&cname,cached)) goto DIE;
67 - goto CNAME;
68 + if (!z->level) {
69 + if (!move_name_to_alias(z,ttl)) goto DIE ;
70 + }
71 + if (!dns_domain_copy(&z->name[z->level],cached)) goto DIE;
72 + goto NEWNAME;
73 }
74
75 if (typematch(DNS_T_NS,dtype)) {
76 @@ -351,7 +370,7 @@
77 }
78 }
79
80 - 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)) {
81 + 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)) {
82 byte_copy(key,2,dtype);
83 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
84 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
85 @@ -471,29 +490,31 @@
86 if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */
87
88 flagout = 0;
89 - flagcname = 0;
90 flagreferral = 0;
91 flagsoa = 0;
92 soattl = 0;
93 - cnamettl = 0;
94 + if (!dns_domain_copy(&owner_name,d)) goto DIE;
95 + /* This code assumes that the CNAME chain is presented in the correct
96 + ** order. The example algorithm in RFC 1034 will actually result in this
97 + ** being the case, but the words do not require it to be so.
98 + */
99 for (j = 0;j < numanswers;++j) {
100 pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
101 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
102
103 - if (dns_domain_equal(t1,d))
104 + if (dns_domain_equal(t1,owner_name))
105 if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */
106 if (typematch(header,dtype))
107 flagout = 1;
108 else if (typematch(header,DNS_T_CNAME)) {
109 - if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE;
110 - flagcname = 1;
111 - cnamettl = ttlget(header + 4);
112 + if (!dns_packet_getname(buf,len,pos,&owner_name)) goto DIE;
113 }
114 }
115
116 uint16_unpack_big(header + 8,&datalen);
117 pos += datalen;
118 }
119 + dns_domain_free(&owner_name) ;
120 posauthority = pos;
121
122 for (j = 0;j < numauthority;++j) {
123 @@ -515,15 +536,6 @@
124 }
125 posglue = pos;
126
127 -
128 - if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
129 - if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
130 - log_lame(whichserver,control,referral);
131 - byte_zero(whichserver,4);
132 - goto HAVENS;
133 - }
134 -
135 -
136 if (records) { alloc_free(records); records = 0; }
137
138 k = numanswers + numauthority + numglue;
139 @@ -670,24 +682,36 @@
140
141 alloc_free(records); records = 0;
142
143 + if (byte_diff(DNS_T_CNAME,2,dtype)) {
144 + /* This code assumes that the CNAME chain is presented in the correct
145 + ** order. The example algorithm in RFC 1034 will actually result in this
146 + ** being the case, but the words do not require it to be so.
147 + */
148 + pos = posanswers;
149 + for (j = 0;j < numanswers;++j) {
150 + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE;
151 + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
152 +
153 + if (dns_domain_equal(t1,d))
154 + if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */
155 + if (typematch(header,DNS_T_CNAME)) {
156 + ttl = ttlget(header + 4);
157 + if (z->level == 0) {
158 + if (!move_name_to_alias(z,ttl)) goto DIE ;
159 + }
160 + if (!dns_packet_getname(buf,len,pos,&z->name[z->level])) goto DIE;
161 + d = z->name[z->level];
162 + if (!dns_domain_suffix(d,control) || !roots_same(d,control))
163 + goto NEWNAME ; /* Cannot trust the chain further - restart using current name */
164 + }
165 + }
166
167 - if (flagcname) {
168 - ttl = cnamettl;
169 - CNAME:
170 - if (!z->level) {
171 - if (z->alias[QUERY_MAXALIAS - 1]) goto DIE;
172 - for (j = QUERY_MAXALIAS - 1;j > 0;--j)
173 - z->alias[j] = z->alias[j - 1];
174 - for (j = QUERY_MAXALIAS - 1;j > 0;--j)
175 - z->aliasttl[j] = z->aliasttl[j - 1];
176 - z->alias[0] = z->name[0];
177 - z->aliasttl[0] = ttl;
178 - z->name[0] = 0;
179 + uint16_unpack_big(header + 8,&datalen);
180 + pos += datalen;
181 }
182 - if (!dns_domain_copy(&z->name[z->level],cname)) goto DIE;
183 - goto NEWNAME;
184 }
185
186 + /* A "no such name" error applies to the end of any CNAME chain, not to the start. */
187 if (rcode == 3) {
188 log_nxdomain(whichserver,d,soattl);
189 cachegeneric(DNS_T_ANY,d,"",0,soattl);
190 @@ -700,10 +724,26 @@
191 return 1;
192 }
193
194 + /* We check for a lame server _after_ we have cached any records that it
195 + ** might have returned to us. This copes better with the incorrect
196 + ** behaviour of one content DNS server software that doesn't return
197 + ** complete CNAME chains but instead returns only the first link in a
198 + ** chain followed by a lame delegation to the same server.
199 + ** Also: We check for a lame server _after_ following the CNAME chain. The
200 + ** delegation in a referral answer applies to the _end_ of the chain, not
201 + ** to the beginning.
202 + */
203 + if (!rcode && !flagout && flagreferral && !flagsoa)
204 + if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
205 + log_lame(whichserver,control,referral);
206 + byte_zero(whichserver,4);
207 + goto HAVENS;
208 + }
209 +
210 if (!flagout && flagsoa)
211 + /* Don't save empty RRSets for those types that we use as special markers. */
212 if (byte_diff(DNS_T_ANY,2,dtype))
213 - if (byte_diff(DNS_T_AXFR,2,dtype))
214 - if (byte_diff(DNS_T_CNAME,2,dtype)) {
215 + if (byte_diff(DNS_T_AXFR,2,dtype)) {
216 save_start();
217 save_finish(dtype,d,soattl);
218 log_nodata(whichserver,d,dtype,soattl);
219 @@ -815,6 +855,7 @@
220 DIE:
221 cleanup(z);
222 if (records) { alloc_free(records); records = 0; }
223 + dns_domain_free(&owner_name) ;
224 return -1;
225 }
226