]>
Commit | Line | Data |
---|---|---|
fbcc3cb7 MF |
1 | From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00 2001 |
2 | From: Simon Kelley <simon@thekelleys.org.uk> | |
3 | Date: Tue, 15 Dec 2015 16:11:06 +0000 | |
4 | Subject: [PATCH] Move code which caches DS records to a more logical place. | |
5 | ||
6 | --- | |
7 | src/dnssec.c | 179 +++++++++++++++++++++++++++++----------------------------- | |
8 | 1 file changed, 90 insertions(+), 89 deletions(-) | |
9 | ||
10 | diff --git a/src/dnssec.c b/src/dnssec.c | |
11 | index 1ae03a6..359231f 100644 | |
12 | --- a/src/dnssec.c | |
13 | +++ b/src/dnssec.c | |
14 | @@ -1204,7 +1204,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch | |
15 | int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class) | |
16 | { | |
17 | unsigned char *p = (unsigned char *)(header+1); | |
18 | - int qtype, qclass, val, i, neganswer, nons; | |
19 | + int qtype, qclass, rc, i, neganswer, nons; | |
20 | + int aclass, atype, rdlen; | |
21 | + unsigned long ttl; | |
22 | + struct all_addr a; | |
23 | ||
24 | if (ntohs(header->qdcount) != 1 || | |
25 | !(p = skip_name(p, header, plen, 4))) | |
26 | @@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char | |
27 | GETSHORT(qclass, p); | |
28 | ||
29 | if (qtype != T_DS || qclass != class) | |
30 | - val = STAT_BOGUS; | |
31 | + rc = STAT_BOGUS; | |
32 | else | |
33 | - val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons); | |
34 | + rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons); | |
35 | /* Note dnssec_validate_reply() will have cached positive answers */ | |
36 | ||
37 | - if (val == STAT_INSECURE) | |
38 | - val = STAT_BOGUS; | |
39 | - | |
40 | + if (rc == STAT_INSECURE) | |
41 | + rc = STAT_BOGUS; | |
42 | + | |
43 | p = (unsigned char *)(header+1); | |
44 | extract_name(header, plen, &p, name, 1, 4); | |
45 | p += 4; /* qtype, qclass */ | |
46 | ||
47 | - if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) | |
48 | - val = STAT_BOGUS; | |
49 | - | |
50 | /* If the key needed to validate the DS is on the same domain as the DS, we'll | |
51 | loop getting nowhere. Stop that now. This can happen of the DS answer comes | |
52 | from the DS's zone, and not the parent zone. */ | |
53 | - if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname))) | |
54 | + if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname))) | |
55 | { | |
56 | log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS"); | |
57 | return STAT_BOGUS; | |
58 | } | |
59 | ||
60 | - if (val != STAT_SECURE) | |
61 | - return val; | |
62 | - | |
63 | - /* By here, the answer is proved secure, and a positive answer has been cached. */ | |
64 | - if (neganswer) | |
65 | + if (rc != STAT_SECURE) | |
66 | + return rc; | |
67 | + | |
68 | + if (!neganswer) | |
69 | { | |
70 | - int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK; | |
71 | - unsigned long ttl, minttl = ULONG_MAX; | |
72 | - struct all_addr a; | |
73 | + cache_start_insert(); | |
74 | + | |
75 | + for (i = 0; i < ntohs(header->ancount); i++) | |
76 | + { | |
77 | + if (!(rc = extract_name(header, plen, &p, name, 0, 10))) | |
78 | + return STAT_BOGUS; /* bad packet */ | |
79 | + | |
80 | + GETSHORT(atype, p); | |
81 | + GETSHORT(aclass, p); | |
82 | + GETLONG(ttl, p); | |
83 | + GETSHORT(rdlen, p); | |
84 | + | |
85 | + if (!CHECK_LEN(header, p, plen, rdlen)) | |
86 | + return STAT_BOGUS; /* bad packet */ | |
87 | + | |
88 | + if (aclass == class && atype == T_DS && rc == 1) | |
89 | + { | |
90 | + int algo, digest, keytag; | |
91 | + unsigned char *psave = p; | |
92 | + struct blockdata *key; | |
93 | + struct crec *crecp; | |
94 | ||
95 | + if (rdlen < 4) | |
96 | + return STAT_BOGUS; /* bad packet */ | |
97 | + | |
98 | + GETSHORT(keytag, p); | |
99 | + algo = *p++; | |
100 | + digest = *p++; | |
101 | + | |
102 | + /* Cache needs to known class for DNSSEC stuff */ | |
103 | + a.addr.dnssec.class = class; | |
104 | + | |
105 | + if ((key = blockdata_alloc((char*)p, rdlen - 4))) | |
106 | + { | |
107 | + if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))) | |
108 | + { | |
109 | + blockdata_free(key); | |
110 | + return STAT_BOGUS; | |
111 | + } | |
112 | + else | |
113 | + { | |
114 | + a.addr.keytag = keytag; | |
115 | + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); | |
116 | + crecp->addr.ds.digest = digest; | |
117 | + crecp->addr.ds.keydata = key; | |
118 | + crecp->addr.ds.algo = algo; | |
119 | + crecp->addr.ds.keytag = keytag; | |
120 | + crecp->addr.ds.keylen = rdlen - 4; | |
121 | + } | |
122 | + } | |
123 | + | |
124 | + p = psave; | |
125 | + | |
126 | + if (!ADD_RDLEN(header, p, plen, rdlen)) | |
127 | + return STAT_BOGUS; /* bad packet */ | |
128 | + } | |
129 | + | |
130 | + cache_end_insert(); | |
131 | + } | |
132 | + } | |
133 | + else | |
134 | + { | |
135 | + int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK; | |
136 | + unsigned long minttl = ULONG_MAX; | |
137 | + | |
138 | + if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) | |
139 | + return STAT_BOGUS; | |
140 | + | |
141 | if (RCODE(header) == NXDOMAIN) | |
142 | flags |= F_NXDOMAIN; | |
143 | ||
144 | @@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char | |
145 | if (!(p = skip_name(p, header, plen, 0))) | |
146 | return STAT_BOGUS; | |
147 | ||
148 | - GETSHORT(qtype, p); | |
149 | - GETSHORT(qclass, p); | |
150 | + GETSHORT(atype, p); | |
151 | + GETSHORT(aclass, p); | |
152 | GETLONG(ttl, p); | |
153 | GETSHORT(rdlen, p); | |
154 | - | |
155 | + | |
156 | if (!CHECK_LEN(header, p, plen, rdlen)) | |
157 | return STAT_BOGUS; /* bad packet */ | |
158 | - | |
159 | - if (qclass != class || qtype != T_SOA) | |
160 | + | |
161 | + if (aclass != class || atype != T_SOA) | |
162 | { | |
163 | p += rdlen; | |
164 | continue; | |
165 | } | |
166 | - | |
167 | + | |
168 | if (ttl < minttl) | |
169 | minttl = ttl; | |
170 | ||
171 | @@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char | |
172 | log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS"); | |
173 | } | |
174 | } | |
175 | - | |
176 | + | |
177 | return STAT_OK; | |
178 | } | |
179 | ||
180 | @@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch | |
181 | /* Not done, validate now */ | |
182 | if (j == i) | |
183 | { | |
184 | - int ttl, keytag, algo, digest, sigcnt, rrcnt; | |
185 | - unsigned char *psave; | |
186 | - struct all_addr a; | |
187 | - struct blockdata *key; | |
188 | - struct crec *crecp; | |
189 | + int sigcnt, rrcnt; | |
190 | char *wildname; | |
191 | ||
192 | if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt)) | |
193 | @@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch | |
194 | Can't overwrite name here. */ | |
195 | strcpy(daemon->workspacename, keyname); | |
196 | rc = zone_status(daemon->workspacename, class1, keyname, now); | |
197 | + | |
198 | if (rc != STAT_SECURE) | |
199 | { | |
200 | /* Zone is insecure, don't need to validate RRset */ | |
201 | @@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch | |
202 | if (rc == STAT_BOGUS) | |
203 | return rc; | |
204 | } | |
205 | - | |
206 | - /* If we just validated a DS RRset, cache it */ | |
207 | - /* Also note if the RRset is the answer to the question, or the target of a CNAME */ | |
208 | - cache_start_insert(); | |
209 | - | |
210 | - for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++) | |
211 | - { | |
212 | - if (!(rc = extract_name(header, plen, &p2, name, 0, 10))) | |
213 | - return STAT_BOGUS; /* bad packet */ | |
214 | - | |
215 | - GETSHORT(type2, p2); | |
216 | - GETSHORT(class2, p2); | |
217 | - GETLONG(ttl, p2); | |
218 | - GETSHORT(rdlen2, p2); | |
219 | - | |
220 | - if (!CHECK_LEN(header, p2, plen, rdlen2)) | |
221 | - return STAT_BOGUS; /* bad packet */ | |
222 | - | |
223 | - if (class2 == class1 && rc == 1) | |
224 | - { | |
225 | - psave = p2; | |
226 | - | |
227 | - if (type1 == T_DS && type2 == T_DS) | |
228 | - { | |
229 | - if (rdlen2 < 4) | |
230 | - return STAT_BOGUS; /* bad packet */ | |
231 | - | |
232 | - GETSHORT(keytag, p2); | |
233 | - algo = *p2++; | |
234 | - digest = *p2++; | |
235 | - | |
236 | - /* Cache needs to known class for DNSSEC stuff */ | |
237 | - a.addr.dnssec.class = class2; | |
238 | - | |
239 | - if ((key = blockdata_alloc((char*)p2, rdlen2 - 4))) | |
240 | - { | |
241 | - if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))) | |
242 | - blockdata_free(key); | |
243 | - else | |
244 | - { | |
245 | - a.addr.keytag = keytag; | |
246 | - log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); | |
247 | - crecp->addr.ds.digest = digest; | |
248 | - crecp->addr.ds.keydata = key; | |
249 | - crecp->addr.ds.algo = algo; | |
250 | - crecp->addr.ds.keytag = keytag; | |
251 | - crecp->addr.ds.keylen = rdlen2 - 4; | |
252 | - } | |
253 | - } | |
254 | - } | |
255 | - | |
256 | - p2 = psave; | |
257 | - } | |
258 | - | |
259 | - if (!ADD_RDLEN(header, p2, plen, rdlen2)) | |
260 | - return STAT_BOGUS; /* bad packet */ | |
261 | - } | |
262 | - | |
263 | - cache_end_insert(); | |
264 | } | |
265 | } | |
266 | } | |
267 | -- | |
268 | 1.7.10.4 | |
269 |