]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/contrib/redirect-bogus.patch
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / contrib / redirect-bogus.patch
1 Index: daemon/worker.c
2 ===================================================================
3 --- daemon/worker.c     (revision 4191)
4 +++ daemon/worker.c     (working copy)
5 @@ -663,8 +663,21 @@
6                 if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
7                         LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
8                         goto bail_out;
9 -               error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
10 -                       qinfo, id, flags, edns);
11 +               if (qinfo->qtype == LDNS_RR_TYPE_A &&
12 +                       worker->env.cfg->redirect_bogus_ipv4) {
13 +                       /* BAD cached */
14 +                       fixed_address_encode(repinfo->c->buffer,
15 +                               LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
16 +                               worker->env.cfg->redirect_bogus_ipv4);
17 +               } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA &&
18 +                       worker->env.cfg->redirect_bogus_ipv6) {
19 +                       fixed_address_encode(repinfo->c->buffer,
20 +                               LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
21 +                               worker->env.cfg->redirect_bogus_ipv6);
22 +               } else {
23 +                       error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
24 +                       qinfo, id, flags, edns);
25 +               }
26                 rrset_array_unlock_touch(worker->env.rrset_cache, 
27                         worker->scratchpad, rep->ref, rep->rrset_count);
28                 if(worker->stats.extended) {
29 Index: doc/unbound.conf.5.in
30 ===================================================================
31 --- doc/unbound.conf.5.in       (revision 4191)
32 +++ doc/unbound.conf.5.in       (working copy)
33 @@ -1244,6 +1244,18 @@
34  This can make ordinary queries complete (if repeatedly queried for),
35  and enter the cache, whilst also mitigating the traffic flow by the
36  factor given.
37 +.TP 5
38 +.B redirect-bogus-ipv4: \fI<IPv4 address>
39 +Set a fixed address for DNSSEC failures that are cached
40 +Instead of responding to A queries with SERVFAIL, respond
41 +with NOERROR and the address specified here
42 +The TTL of the response will be 5 seconds
43 +.TP 5
44 +.B redirect-bogus-ipv6: \fI<IPv4 address>
45 +Set a fixed address for DNSSEC failures that are cached
46 +Instead of responding to AAAA queries with SERVFAIL, respond
47 +with NOERROR and the address specified here
48 +The TTL of the response will be 5 seconds
49  .SS "Remote Control Options"
50  In the
51  .B remote\-control:
52 Index: services/mesh.c
53 ===================================================================
54 --- services/mesh.c     (revision 4191)
55 +++ services/mesh.c     (working copy)
56 @@ -1006,6 +1006,7 @@
57         struct timeval end_time;
58         struct timeval duration;
59         int secure;
60 +       int bogus_override = 0;
61         /* Copy the client's EDNS for later restore, to make sure the edns
62          * compare is with the correct edns options. */
63         struct edns_data edns_bak = r->edns;
64 @@ -1016,6 +1017,7 @@
65                 rcode = LDNS_RCODE_SERVFAIL;
66                 if(m->s.env->cfg->stat_extended) 
67                         m->s.env->mesh->ans_bogus++;
68 +               bogus_override = 1;
69         }
70         if(rep && rep->security == sec_status_secure)
71                 secure = 1;
72 @@ -1047,17 +1049,34 @@
73         } else if(rcode) {
74                 m->s.qinfo.qname = r->qname;
75                 m->s.qinfo.local_alias = r->local_alias;
76 -               if(rcode == LDNS_RCODE_SERVFAIL) {
77 -                       if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
78 -                               rep, rcode, &r->edns, m->s.region))
79 -                                       r->edns.opt_list = NULL;
80 -               } else { 
81 -                       if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
82 -                               &r->edns, m->s.region))
83 -                                       r->edns.opt_list = NULL;
84 +               if(bogus_override && m->s.qinfo.qtype == LDNS_RR_TYPE_A &&
85 +                       m->s.env->cfg->redirect_bogus_ipv4) {
86 +                       fixed_address_encode(r->query_reply.c->buffer,
87 +                               LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
88 +                               r->qflags, &r->edns,
89 +                               m->s.env->cfg->redirect_bogus_ipv4);
90 +               } else if(bogus_override &&
91 +                       m->s.qinfo.qtype == LDNS_RR_TYPE_AAAA &&
92 +                       m->s.env->cfg->redirect_bogus_ipv6) {
93 +                       fixed_address_encode(r->query_reply.c->buffer,
94 +                               LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
95 +                               r->qflags, &r->edns,
96 +                               m->s.env->cfg->redirect_bogus_ipv6);
97 +               } else {
98 +                       if(rcode == LDNS_RCODE_SERVFAIL) {
99 +                               if(!inplace_cb_reply_servfail_call(m->s.env,
100 +                                       &m->s.qinfo, &m->s,
101 +                                       rep, rcode, &r->edns, m->s.region))
102 +                                               r->edns.opt_list = NULL;
103 +                       } else { 
104 +                               if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo,
105 +                                       &m->s, rep, rcode, &r->edns,
106 +                                       m->s.region))
107 +                                               r->edns.opt_list = NULL;
108 +                       }
109 +                       error_encode(r->query_reply.c->buffer, rcode,
110 +                               &m->s.qinfo, r->qid, r->qflags, &r->edns);
111                 }
112 -               error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
113 -                       r->qid, r->qflags, &r->edns);
114                 comm_point_send_reply(&r->query_reply);
115         } else {
116                 size_t udp_size = r->edns.udp_size;
117 Index: util/config_file.c
118 ===================================================================
119 --- util/config_file.c  (revision 4191)
120 +++ util/config_file.c  (working copy)
121 @@ -273,6 +273,8 @@
122         cfg->ratelimit_factor = 10;
123         cfg->qname_minimisation = 0;
124         cfg->qname_minimisation_strict = 0;
125 +       cfg->redirect_bogus_ipv4 = NULL;
126 +       cfg->redirect_bogus_ipv6 = NULL;
127         cfg->shm_enable = 0;
128         cfg->shm_key = 11777;
129         cfg->dnscrypt = 0;
130 @@ -602,6 +604,10 @@
131                 }
132                 oi[cfg->num_out_ifs++] = d;
133                 cfg->out_ifs = oi;
134 +       } else if (strcmp(opt, "redirect-bogus-ipv4:") == 0) {
135 +               cfg->redirect_bogus_ipv4 = strdup(val);
136 +       } else if (strcmp(opt, "redirect-bogus-ipv6:") == 0) {
137 +               cfg->redirect_bogus_ipv6 = strdup(val);
138         } else {
139                 /* unknown or unsupported (from the set_option interface):
140                  * interface, outgoing-interface, access-control,
141 @@ -1250,6 +1256,12 @@
142         free(cfg->dnstap_version);
143         config_deldblstrlist(cfg->ratelimit_for_domain);
144         config_deldblstrlist(cfg->ratelimit_below_domain);
145 +       if (cfg->redirect_bogus_ipv4) {
146 +               free(cfg->redirect_bogus_ipv4);
147 +       }
148 +       if (cfg->redirect_bogus_ipv6) {
149 +               free(cfg->redirect_bogus_ipv6);
150 +       }
151  #ifdef USE_IPSECMOD
152         free(cfg->ipsecmod_hook);
153         config_delstrlist(cfg->ipsecmod_whitelist);
154 Index: util/config_file.h
155 ===================================================================
156 --- util/config_file.h  (revision 4191)
157 +++ util/config_file.h  (working copy)
158 @@ -444,6 +444,9 @@
159         /** minimise QNAME in strict mode, minimise according to RFC.
160          *  Do not apply fallback */
161         int qname_minimisation_strict;
162 +       /** construct fake responses for DNSSEC failures */
163 +       char *redirect_bogus_ipv4;
164 +       char *redirect_bogus_ipv6;
165         /** SHM data - true if shm is enabled */
166         int shm_enable;
167         /** SHM data - key for the shm */
168 Index: util/configlexer.lex
169 ===================================================================
170 --- util/configlexer.lex        (revision 4191)
171 +++ util/configlexer.lex        (working copy)
172 @@ -410,6 +410,8 @@
173  response-ip-tag{COLON}         { YDVAR(2, VAR_RESPONSE_IP_TAG) }
174  response-ip{COLON}             { YDVAR(2, VAR_RESPONSE_IP) }
175  response-ip-data{COLON}                { YDVAR(2, VAR_RESPONSE_IP_DATA) }
176 +redirect-bogus-ipv4{COLON}     { YDVAR(1, VAR_REDIRECT_BOGUS_IPV4) }
177 +redirect-bogus-ipv6{COLON}     { YDVAR(1, VAR_REDIRECT_BOGUS_IPV6) }
178  dnscrypt{COLON}                        { YDVAR(0, VAR_DNSCRYPT) }
179  dnscrypt-enable{COLON}         { YDVAR(1, VAR_DNSCRYPT_ENABLE) }
180  dnscrypt-port{COLON}           { YDVAR(1, VAR_DNSCRYPT_PORT) }
181 Index: util/configparser.y
182 ===================================================================
183 --- util/configparser.y (revision 4191)
184 +++ util/configparser.y (working copy)
185 @@ -44,6 +44,7 @@
186  #include <stdlib.h>
187  #include <assert.h>
188  
189 +#include "sldns/str2wire.h"
190  #include "util/configyyrename.h"
191  #include "util/config_file.h"
192  #include "util/net_help.h"
193 @@ -141,6 +142,7 @@
194  %token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
195  %token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1
196  %token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
197 +%token VAR_REDIRECT_BOGUS_IPV4 VAR_REDIRECT_BOGUS_IPV6
198  %token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
199  %token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
200  %token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
201 @@ -228,6 +230,7 @@
202         server_access_control_tag_data | server_access_control_view |
203         server_qname_minimisation_strict | server_serve_expired |
204         server_fake_dsa | server_log_identity | server_use_systemd |
205 +       server_redirect_bogus_ipv4 | server_redirect_bogus_ipv6 |
206         server_response_ip_tag | server_response_ip | server_response_ip_data |
207         server_shm_enable | server_shm_key | server_fake_sha1 |
208         server_hide_trustanchor | server_trust_anchor_signaling |
209 @@ -1873,6 +1876,34 @@
210         #endif
211         }
212         ;
213 +server_redirect_bogus_ipv4: VAR_REDIRECT_BOGUS_IPV4 STRING_ARG
214 +       {
215 +               uint8_t data[4];
216 +               size_t data_len = 4;
217 +               OUTYY(("P(name:%s)\n", $2));
218 +               if(cfg_parser->cfg->redirect_bogus_ipv4) {
219 +                       yyerror("redirect-bogus-ipv4, can only use one address");
220 +               }
221 +               if(sldns_str2wire_a_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
222 +                       yyerror("redirect-bogus-ipv4, not a valid IPv4 address");
223 +               }
224 +               free(cfg_parser->cfg->redirect_bogus_ipv4);
225 +               cfg_parser->cfg->redirect_bogus_ipv4 = $2;
226 +       }
227 +server_redirect_bogus_ipv6: VAR_REDIRECT_BOGUS_IPV6 STRING_ARG
228 +       {
229 +               uint8_t data[16];
230 +               size_t data_len = 16;
231 +               OUTYY(("P(name:%s)\n", $2));
232 +               if(cfg_parser->cfg->redirect_bogus_ipv6) {
233 +                       yyerror("redirect-bogus-ipv6, can only use one address");
234 +               }
235 +               if(sldns_str2wire_aaaa_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
236 +                       yyerror("redirect-bogus-ipv6, not a valid IPv6 address");
237 +               }
238 +               free(cfg_parser->cfg->redirect_bogus_ipv6);
239 +               cfg_parser->cfg->redirect_bogus_ipv6 = $2;
240 +       }
241  stub_name: VAR_NAME STRING_ARG
242         {
243                 OUTYY(("P(name:%s)\n", $2));
244 Index: util/data/msgencode.c
245 ===================================================================
246 --- util/data/msgencode.c       (revision 4191)
247 +++ util/data/msgencode.c       (working copy)
248 @@ -48,6 +48,7 @@
249  #include "util/regional.h"
250  #include "util/net_help.h"
251  #include "sldns/sbuffer.h"
252 +#include "sldns/str2wire.h"
253  #include "services/localzone.h"
254  
255  /** return code that means the function ran out of memory. negative so it does
256 @@ -914,3 +915,63 @@
257                 attach_edns_record(buf, &es);
258         }
259  }
260 +
261 +void 
262 +fixed_address_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
263 +       uint16_t qid, uint16_t qflags, struct edns_data* edns, char* data)
264 +{
265 +       uint16_t flags;
266 +       uint8_t addr_data[16];
267 +       size_t addr_len = 16;
268 +       if (qinfo->qtype == LDNS_RR_TYPE_A) {
269 +               sldns_str2wire_a_buf(data, addr_data, &addr_len);
270 +       } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA) {
271 +               sldns_str2wire_aaaa_buf(data, addr_data, &addr_len);
272 +       } else {
273 +               return error_encode(buf, LDNS_RCODE_NOERROR, qinfo, qid, qflags, edns);
274 +       }
275 +       sldns_buffer_clear(buf);
276 +       sldns_buffer_write(buf, &qid, sizeof(uint16_t));
277 +       flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
278 +       flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
279 +       sldns_buffer_write_u16(buf, flags);
280 +       if(qinfo) flags = 1;
281 +       else    flags = 0;
282 +       sldns_buffer_write_u16(buf, flags);
283 +       sldns_buffer_write_u16(buf, 1);
284 +       flags = 0;
285 +       sldns_buffer_write(buf, &flags, sizeof(uint16_t));
286 +       sldns_buffer_write(buf, &flags, sizeof(uint16_t));
287 +       if(qinfo) {
288 +               // query
289 +               if(sldns_buffer_current(buf) == qinfo->qname)
290 +                       sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
291 +               else    sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
292 +               sldns_buffer_write_u16(buf, qinfo->qtype);
293 +               sldns_buffer_write_u16(buf, qinfo->qclass);
294 +               // faked answer
295 +               if(sldns_buffer_current(buf) == qinfo->qname)
296 +                       sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
297 +               else    sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
298 +               sldns_buffer_write_u16(buf, qinfo->qtype);
299 +               sldns_buffer_write_u16(buf, qinfo->qclass);
300 +               sldns_buffer_write_u16(buf, 0);
301 +               // TTL. Should we make this configurable too?
302 +               sldns_buffer_write_u16(buf, 5);
303 +               sldns_buffer_write_u16(buf, addr_len);
304 +               sldns_buffer_write(buf, addr_data, addr_len);
305 +               fflush(stderr);
306 +       }
307 +       sldns_buffer_flip(buf);
308 +       if(edns) {
309 +               struct edns_data es = *edns;
310 +               es.edns_version = EDNS_ADVERTISED_VERSION;
311 +               es.udp_size = EDNS_ADVERTISED_SIZE;
312 +               es.ext_rcode = 0;
313 +               es.bits &= EDNS_DO;
314 +               if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
315 +                       edns->udp_size)
316 +                       return;
317 +               attach_edns_record(buf, &es);
318 +       }
319 +}
320 Index: util/data/msgencode.h
321 ===================================================================
322 --- util/data/msgencode.h       (revision 4191)
323 +++ util/data/msgencode.h       (working copy)
324 @@ -128,4 +128,20 @@
325  void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
326         uint16_t qid, uint16_t qflags, struct edns_data* edns);
327  
328 +/**
329 + * Encode a fixed address response.
330 + * This is a fake answer to either an A or AAA query
331 + *
332 + * It will answer with that address
333 + *
334 + * @param pkt: where to store the packet.
335 + * @param r: RCODE value to encode.
336 + * @param qinfo: if not NULL, the query is included.
337 + * @param qid: query ID to set in packet. network order.
338 + * @param qflags: original query flags (to copy RD and CD bits). host order.
339 + * @param edns: if not NULL, this is the query edns info,
340 + *     and an edns reply is attached. Only attached if EDNS record fits reply.
341 + */
342 +void fixed_address_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
343 +       uint16_t qid, uint16_t qflags, struct edns_data* edns, char* address);
344  #endif /* UTIL_DATA_MSGENCODE_H */