2 ===================================================================
3 --- daemon/worker.c (revision 4191)
4 +++ daemon/worker.c (working copy)
6 if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
7 LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
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) {
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);
23 + error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
24 + qinfo, id, flags, edns);
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
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
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"
52 Index: services/mesh.c
53 ===================================================================
54 --- services/mesh.c (revision 4191)
55 +++ services/mesh.c (working copy)
57 struct timeval end_time;
58 struct timeval duration;
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;
65 rcode = LDNS_RCODE_SERVFAIL;
66 if(m->s.env->cfg->stat_extended)
67 m->s.env->mesh->ans_bogus++;
70 if(rep && rep->security == sec_status_secure)
72 @@ -1047,17 +1049,34 @@
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;
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);
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;
104 + if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo,
105 + &m->s, rep, rcode, &r->edns,
107 + r->edns.opt_list = NULL;
109 + error_encode(r->query_reply.c->buffer, rcode,
110 + &m->s.qinfo, r->qid, r->qflags, &r->edns);
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);
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)
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;
128 cfg->shm_key = 11777;
132 oi[cfg->num_out_ifs++] = d;
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);
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);
148 + if (cfg->redirect_bogus_ipv6) {
149 + free(cfg->redirect_bogus_ipv6);
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)
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 */
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)
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)
189 +#include "sldns/str2wire.h"
190 #include "util/configyyrename.h"
191 #include "util/config_file.h"
192 #include "util/net_help.h"
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
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 @@
213 +server_redirect_bogus_ipv4: VAR_REDIRECT_BOGUS_IPV4 STRING_ARG
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");
221 + if(sldns_str2wire_a_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
222 + yyerror("redirect-bogus-ipv4, not a valid IPv4 address");
224 + free(cfg_parser->cfg->redirect_bogus_ipv4);
225 + cfg_parser->cfg->redirect_bogus_ipv4 = $2;
227 +server_redirect_bogus_ipv6: VAR_REDIRECT_BOGUS_IPV6 STRING_ARG
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");
235 + if(sldns_str2wire_aaaa_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
236 + yyerror("redirect-bogus-ipv6, not a valid IPv6 address");
238 + free(cfg_parser->cfg->redirect_bogus_ipv6);
239 + cfg_parser->cfg->redirect_bogus_ipv6 = $2;
241 stub_name: VAR_NAME STRING_ARG
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)
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"
255 /** return code that means the function ran out of memory. negative so it does
257 attach_edns_record(buf, &es);
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)
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);
273 + return error_encode(buf, LDNS_RCODE_NOERROR, qinfo, qid, qflags, edns);
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;
282 + sldns_buffer_write_u16(buf, flags);
283 + sldns_buffer_write_u16(buf, 1);
285 + sldns_buffer_write(buf, &flags, sizeof(uint16_t));
286 + sldns_buffer_write(buf, &flags, sizeof(uint16_t));
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);
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);
307 + sldns_buffer_flip(buf);
309 + struct edns_data es = *edns;
310 + es.edns_version = EDNS_ADVERTISED_VERSION;
311 + es.udp_size = EDNS_ADVERTISED_SIZE;
313 + es.bits &= EDNS_DO;
314 + if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
317 + attach_edns_record(buf, &es);
320 Index: util/data/msgencode.h
321 ===================================================================
322 --- util/data/msgencode.h (revision 4191)
323 +++ util/data/msgencode.h (working copy)
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);
329 + * Encode a fixed address response.
330 + * This is a fake answer to either an A or AAA query
332 + * It will answer with that address
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.
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 */