1Index: 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) { 29Index: 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: 52Index: 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; 117Index: 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); 154Index: 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 */ 168Index: 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) } 181Index: 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)); 244Index: 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+} 320Index: 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 */ 345