]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/dnsmasq/0070-Return-INSECURE-rather-than-BOGUS-when-DS-proved-not.patch
Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into next
[ipfire-2.x.git] / src / patches / dnsmasq / 0070-Return-INSECURE-rather-than-BOGUS-when-DS-proved-not.patch
1 From fe3992f9fa69fa975ea31919c53933b5f6a63527 Mon Sep 17 00:00:00 2001
2 From: Simon Kelley <simon@thekelleys.org.uk>
3 Date: Fri, 3 Apr 2015 21:25:05 +0100
4 Subject: [PATCH 70/78] Return INSECURE, rather than BOGUS when DS proved not
5 to exist.
6
7 Return INSECURE when validating DNS replies which have RRSIGs, but
8 when a needed DS record in the trust chain is proved not to exist.
9 It's allowed for a zone to set up DNSKEY and RRSIG records first, then
10 add a DS later, completing the chain of trust.
11
12 Also, since we don't have the infrastructure to track that these
13 non-validated replies have RRSIGS, don't cache them, so we don't
14 provide answers with missing RRSIGS from the cache.
15 ---
16 src/dnsmasq.h | 1 +
17 src/dnssec.c | 2 +-
18 src/forward.c | 87 +++++++++++++++++++++++++++++++++++++++++++++--------------
19 3 files changed, 69 insertions(+), 21 deletions(-)
20
21 diff --git a/src/dnsmasq.h b/src/dnsmasq.h
22 index 42952fc76c7a..6fe4a4189188 100644
23 --- a/src/dnsmasq.h
24 +++ b/src/dnsmasq.h
25 @@ -583,6 +583,7 @@ struct hostsfile {
26 #define STAT_NO_NS 10
27 #define STAT_NEED_DS_NEG 11
28 #define STAT_CHASE_CNAME 12
29 +#define STAT_INSECURE_DS 13
30
31 #define FREC_NOREBIND 1
32 #define FREC_CHECKING_DISABLED 2
33 diff --git a/src/dnssec.c b/src/dnssec.c
34 index 14bae7e9bf75..05e0983cb251 100644
35 --- a/src/dnssec.c
36 +++ b/src/dnssec.c
37 @@ -981,7 +981,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
38
39 /* If we've cached that DS provably doesn't exist, result must be INSECURE */
40 if (crecp->flags & F_NEG)
41 - return STAT_INSECURE;
42 + return STAT_INSECURE_DS;
43
44 /* NOTE, we need to find ONE DNSKEY which matches the DS */
45 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
46 diff --git a/src/forward.c b/src/forward.c
47 index 985814c3aec5..e8cf615aa939 100644
48 --- a/src/forward.c
49 +++ b/src/forward.c
50 @@ -521,7 +521,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
51 }
52
53 static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
54 - int no_cache, int cache_secure, int ad_reqd, int do_bit, int added_pheader, int check_subnet, union mysockaddr *query_source)
55 + int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
56 + int check_subnet, union mysockaddr *query_source)
57 {
58 unsigned char *pheader, *sizep;
59 char **sets = 0;
60 @@ -634,7 +635,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
61 }
62
63 #ifdef HAVE_DNSSEC
64 - if (no_cache && !(header->hb4 & HB4_CD))
65 + if (bogusanswer && !(header->hb4 & HB4_CD))
66 {
67 if (!option_bool(OPT_DNSSEC_DEBUG))
68 {
69 @@ -786,7 +787,7 @@ void reply_query(int fd, int family, time_t now)
70 everything is broken */
71 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
72 {
73 - int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0;
74 + int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
75
76 if (option_bool(OPT_NO_REBIND))
77 check_rebind = !(forward->flags & FREC_NOREBIND);
78 @@ -819,7 +820,13 @@ void reply_query(int fd, int family, time_t now)
79 else if (forward->flags & FREC_DS_QUERY)
80 {
81 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
82 - if (status == STAT_NO_DS || status == STAT_NO_NS)
83 + /* Provably no DS, everything below is insecure, even if signatures are offered */
84 + if (status == STAT_NO_DS)
85 + /* We only cache sigs when we've validated a reply.
86 + Avoid caching a reply with sigs if there's a vaildated break in the
87 + DS chain, so we don't return replies from cache missing sigs. */
88 + status = STAT_INSECURE_DS;
89 + else if (status == STAT_NO_NS)
90 status = STAT_BOGUS;
91 }
92 else if (forward->flags & FREC_CHECK_NOSIGN)
93 @@ -959,8 +966,14 @@ void reply_query(int fd, int family, time_t now)
94 else if (forward->flags & FREC_DS_QUERY)
95 {
96 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
97 - if (status == STAT_NO_DS || status == STAT_NO_NS)
98 - status = STAT_BOGUS;
99 + /* Provably no DS, everything below is insecure, even if signatures are offered */
100 + if (status == STAT_NO_DS)
101 + /* We only cache sigs when we've validated a reply.
102 + Avoid caching a reply with sigs if there's a vaildated break in the
103 + DS chain, so we don't return replies from cache missing sigs. */
104 + status = STAT_INSECURE_DS;
105 + else if (status == STAT_NO_NS)
106 + status = STAT_BOGUS;
107 }
108 else if (forward->flags & FREC_CHECK_NOSIGN)
109 {
110 @@ -985,6 +998,17 @@ void reply_query(int fd, int family, time_t now)
111 }
112 }
113
114 + no_cache_dnssec = 0;
115 +
116 + if (status == STAT_INSECURE_DS)
117 + {
118 + /* We only cache sigs when we've validated a reply.
119 + Avoid caching a reply with sigs if there's a vaildated break in the
120 + DS chain, so we don't return replies from cache missing sigs. */
121 + status = STAT_INSECURE;
122 + no_cache_dnssec = 1;
123 + }
124 +
125 if (status == STAT_TRUNCATED)
126 header->hb3 |= HB3_TC;
127 else
128 @@ -1002,12 +1026,13 @@ void reply_query(int fd, int family, time_t now)
129 log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
130 }
131
132 - no_cache_dnssec = 0;
133 -
134 if (status == STAT_SECURE)
135 cache_secure = 1;
136 else if (status == STAT_BOGUS)
137 - no_cache_dnssec = 1;
138 + {
139 + no_cache_dnssec = 1;
140 + bogusanswer = 1;
141 + }
142 }
143 #endif
144
145 @@ -1017,7 +1042,7 @@ void reply_query(int fd, int family, time_t now)
146 else
147 header->hb4 &= ~HB4_CD;
148
149 - if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure,
150 + if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
151 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
152 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
153 {
154 @@ -1420,7 +1445,7 @@ static int do_check_sign(struct frec *forward, int status, time_t now, char *nam
155 }
156 }
157
158 -/* Move toward the root, until we find a signed non-existance of a DS, in which case
159 +/* Move down from the root, until we find a signed non-existance of a DS, in which case
160 an unsigned answer is OK, or we find a signed DS, in which case there should be
161 a signature, and the answer is BOGUS */
162 static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name,
163 @@ -1570,8 +1595,13 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
164 else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
165 {
166 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
167 - if (status == STAT_NEED_DS && (new_status == STAT_NO_DS || new_status == STAT_NO_NS))
168 - new_status = STAT_BOGUS;
169 + if (status == STAT_NEED_DS)
170 + {
171 + if (new_status == STAT_NO_DS)
172 + new_status = STAT_INSECURE_DS;
173 + else if (new_status == STAT_NO_NS)
174 + new_status = STAT_BOGUS;
175 + }
176 }
177 else if (status == STAT_CHASE_CNAME)
178 new_status = dnssec_chase_cname(now, header, n, name, keyname);
179 @@ -1630,8 +1660,13 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
180 else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
181 {
182 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
183 - if (status == STAT_NEED_DS && (new_status == STAT_NO_DS || new_status == STAT_NO_NS))
184 - new_status = STAT_BOGUS; /* Validated no DS */
185 + if (status == STAT_NEED_DS)
186 + {
187 + if (new_status == STAT_NO_DS)
188 + new_status = STAT_INSECURE_DS;
189 + else if (new_status == STAT_NO_NS)
190 + new_status = STAT_BOGUS; /* Validated no DS */
191 + }
192 }
193 else if (status == STAT_CHASE_CNAME)
194 new_status = dnssec_chase_cname(now, header, n, name, keyname);
195 @@ -1652,7 +1687,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
196 goto another_tcp_key;
197 }
198 }
199 -
200 +
201 free(packet);
202 }
203 return new_status;
204 @@ -1673,7 +1708,7 @@ unsigned char *tcp_request(int confd, time_t now,
205 int local_auth = 0;
206 #endif
207 int checking_disabled, ad_question, do_bit, added_pheader = 0;
208 - int check_subnet, no_cache_dnssec = 0, cache_secure = 0;
209 + int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
210 size_t m;
211 unsigned short qtype;
212 unsigned int gotname;
213 @@ -1941,6 +1976,15 @@ unsigned char *tcp_request(int confd, time_t now,
214 int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
215 char *result;
216
217 + if (status == STAT_INSECURE_DS)
218 + {
219 + /* We only cache sigs when we've validated a reply.
220 + Avoid caching a reply with sigs if there's a vaildated break in the
221 + DS chain, so we don't return replies from cache missing sigs. */
222 + status = STAT_INSECURE;
223 + no_cache_dnssec = 1;
224 + }
225 +
226 if (keycount == 0)
227 {
228 result = "ABANDONED";
229 @@ -1952,8 +1996,11 @@ unsigned char *tcp_request(int confd, time_t now,
230 log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
231
232 if (status == STAT_BOGUS)
233 - no_cache_dnssec = 1;
234 -
235 + {
236 + no_cache_dnssec = 1;
237 + bogusanswer = 1;
238 + }
239 +
240 if (status == STAT_SECURE)
241 cache_secure = 1;
242 }
243 @@ -1987,7 +2034,7 @@ unsigned char *tcp_request(int confd, time_t now,
244 #endif
245
246 m = process_reply(header, now, last_server, (unsigned int)m,
247 - option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec,
248 + option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, bogusanswer,
249 cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
250
251 break;
252 --
253 2.1.0
254