1333537SdesIndex: daemon/worker.c 2333537Sdes=================================================================== 3333537Sdes--- daemon/worker.c (revision 4191) 4333537Sdes+++ daemon/worker.c (working copy) 5333537Sdes@@ -663,8 +663,21 @@ 6333537Sdes if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, 7333537Sdes LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) 8333537Sdes goto bail_out; 9333537Sdes- error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 10333537Sdes- qinfo, id, flags, edns); 11333537Sdes+ if (qinfo->qtype == LDNS_RR_TYPE_A && 12333537Sdes+ worker->env.cfg->redirect_bogus_ipv4) { 13333537Sdes+ /* BAD cached */ 14333537Sdes+ fixed_address_encode(repinfo->c->buffer, 15333537Sdes+ LDNS_RCODE_NOERROR, qinfo, id, flags, edns, 16333537Sdes+ worker->env.cfg->redirect_bogus_ipv4); 17333537Sdes+ } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA && 18333537Sdes+ worker->env.cfg->redirect_bogus_ipv6) { 19333537Sdes+ fixed_address_encode(repinfo->c->buffer, 20333537Sdes+ LDNS_RCODE_NOERROR, qinfo, id, flags, edns, 21333537Sdes+ worker->env.cfg->redirect_bogus_ipv6); 22333537Sdes+ } else { 23333537Sdes+ error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 24333537Sdes+ qinfo, id, flags, edns); 25333537Sdes+ } 26333537Sdes rrset_array_unlock_touch(worker->env.rrset_cache, 27333537Sdes worker->scratchpad, rep->ref, rep->rrset_count); 28333537Sdes if(worker->stats.extended) { 29333537SdesIndex: doc/unbound.conf.5.in 30333537Sdes=================================================================== 31333537Sdes--- doc/unbound.conf.5.in (revision 4191) 32333537Sdes+++ doc/unbound.conf.5.in (working copy) 33333537Sdes@@ -1244,6 +1244,18 @@ 34333537Sdes This can make ordinary queries complete (if repeatedly queried for), 35333537Sdes and enter the cache, whilst also mitigating the traffic flow by the 36333537Sdes factor given. 37333537Sdes+.TP 5 38333537Sdes+.B redirect-bogus-ipv4: \fI<IPv4 address> 39333537Sdes+Set a fixed address for DNSSEC failures that are cached 40333537Sdes+Instead of responding to A queries with SERVFAIL, respond 41333537Sdes+with NOERROR and the address specified here 42333537Sdes+The TTL of the response will be 5 seconds 43333537Sdes+.TP 5 44333537Sdes+.B redirect-bogus-ipv6: \fI<IPv4 address> 45333537Sdes+Set a fixed address for DNSSEC failures that are cached 46333537Sdes+Instead of responding to AAAA queries with SERVFAIL, respond 47333537Sdes+with NOERROR and the address specified here 48333537Sdes+The TTL of the response will be 5 seconds 49333537Sdes .SS "Remote Control Options" 50333537Sdes In the 51333537Sdes .B remote\-control: 52333537SdesIndex: services/mesh.c 53333537Sdes=================================================================== 54333537Sdes--- services/mesh.c (revision 4191) 55333537Sdes+++ services/mesh.c (working copy) 56333537Sdes@@ -1006,6 +1006,7 @@ 57333537Sdes struct timeval end_time; 58333537Sdes struct timeval duration; 59333537Sdes int secure; 60333537Sdes+ int bogus_override = 0; 61333537Sdes /* Copy the client's EDNS for later restore, to make sure the edns 62333537Sdes * compare is with the correct edns options. */ 63333537Sdes struct edns_data edns_bak = r->edns; 64333537Sdes@@ -1016,6 +1017,7 @@ 65333537Sdes rcode = LDNS_RCODE_SERVFAIL; 66333537Sdes if(m->s.env->cfg->stat_extended) 67333537Sdes m->s.env->mesh->ans_bogus++; 68333537Sdes+ bogus_override = 1; 69333537Sdes } 70333537Sdes if(rep && rep->security == sec_status_secure) 71333537Sdes secure = 1; 72333537Sdes@@ -1047,17 +1049,34 @@ 73333537Sdes } else if(rcode) { 74333537Sdes m->s.qinfo.qname = r->qname; 75333537Sdes m->s.qinfo.local_alias = r->local_alias; 76333537Sdes- if(rcode == LDNS_RCODE_SERVFAIL) { 77333537Sdes- if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, 78333537Sdes- rep, rcode, &r->edns, m->s.region)) 79333537Sdes- r->edns.opt_list = NULL; 80333537Sdes- } else { 81333537Sdes- if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, 82333537Sdes- &r->edns, m->s.region)) 83333537Sdes- r->edns.opt_list = NULL; 84333537Sdes+ if(bogus_override && m->s.qinfo.qtype == LDNS_RR_TYPE_A && 85333537Sdes+ m->s.env->cfg->redirect_bogus_ipv4) { 86333537Sdes+ fixed_address_encode(r->query_reply.c->buffer, 87333537Sdes+ LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid, 88333537Sdes+ r->qflags, &r->edns, 89333537Sdes+ m->s.env->cfg->redirect_bogus_ipv4); 90333537Sdes+ } else if(bogus_override && 91333537Sdes+ m->s.qinfo.qtype == LDNS_RR_TYPE_AAAA && 92333537Sdes+ m->s.env->cfg->redirect_bogus_ipv6) { 93333537Sdes+ fixed_address_encode(r->query_reply.c->buffer, 94333537Sdes+ LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid, 95333537Sdes+ r->qflags, &r->edns, 96333537Sdes+ m->s.env->cfg->redirect_bogus_ipv6); 97333537Sdes+ } else { 98333537Sdes+ if(rcode == LDNS_RCODE_SERVFAIL) { 99333537Sdes+ if(!inplace_cb_reply_servfail_call(m->s.env, 100333537Sdes+ &m->s.qinfo, &m->s, 101333537Sdes+ rep, rcode, &r->edns, m->s.region)) 102333537Sdes+ r->edns.opt_list = NULL; 103333537Sdes+ } else { 104333537Sdes+ if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, 105333537Sdes+ &m->s, rep, rcode, &r->edns, 106333537Sdes+ m->s.region)) 107333537Sdes+ r->edns.opt_list = NULL; 108333537Sdes+ } 109333537Sdes+ error_encode(r->query_reply.c->buffer, rcode, 110333537Sdes+ &m->s.qinfo, r->qid, r->qflags, &r->edns); 111333537Sdes } 112333537Sdes- error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo, 113333537Sdes- r->qid, r->qflags, &r->edns); 114333537Sdes comm_point_send_reply(&r->query_reply); 115333537Sdes } else { 116333537Sdes size_t udp_size = r->edns.udp_size; 117333537SdesIndex: util/config_file.c 118333537Sdes=================================================================== 119333537Sdes--- util/config_file.c (revision 4191) 120333537Sdes+++ util/config_file.c (working copy) 121333537Sdes@@ -273,6 +273,8 @@ 122333537Sdes cfg->ratelimit_factor = 10; 123333537Sdes cfg->qname_minimisation = 0; 124333537Sdes cfg->qname_minimisation_strict = 0; 125333537Sdes+ cfg->redirect_bogus_ipv4 = NULL; 126333537Sdes+ cfg->redirect_bogus_ipv6 = NULL; 127333537Sdes cfg->shm_enable = 0; 128333537Sdes cfg->shm_key = 11777; 129333537Sdes cfg->dnscrypt = 0; 130333537Sdes@@ -602,6 +604,10 @@ 131333537Sdes } 132333537Sdes oi[cfg->num_out_ifs++] = d; 133333537Sdes cfg->out_ifs = oi; 134333537Sdes+ } else if (strcmp(opt, "redirect-bogus-ipv4:") == 0) { 135333537Sdes+ cfg->redirect_bogus_ipv4 = strdup(val); 136333537Sdes+ } else if (strcmp(opt, "redirect-bogus-ipv6:") == 0) { 137333537Sdes+ cfg->redirect_bogus_ipv6 = strdup(val); 138333537Sdes } else { 139333537Sdes /* unknown or unsupported (from the set_option interface): 140333537Sdes * interface, outgoing-interface, access-control, 141333537Sdes@@ -1250,6 +1256,12 @@ 142333537Sdes free(cfg->dnstap_version); 143333537Sdes config_deldblstrlist(cfg->ratelimit_for_domain); 144333537Sdes config_deldblstrlist(cfg->ratelimit_below_domain); 145333537Sdes+ if (cfg->redirect_bogus_ipv4) { 146333537Sdes+ free(cfg->redirect_bogus_ipv4); 147333537Sdes+ } 148333537Sdes+ if (cfg->redirect_bogus_ipv6) { 149333537Sdes+ free(cfg->redirect_bogus_ipv6); 150333537Sdes+ } 151333537Sdes #ifdef USE_IPSECMOD 152333537Sdes free(cfg->ipsecmod_hook); 153333537Sdes config_delstrlist(cfg->ipsecmod_whitelist); 154333537SdesIndex: util/config_file.h 155333537Sdes=================================================================== 156333537Sdes--- util/config_file.h (revision 4191) 157333537Sdes+++ util/config_file.h (working copy) 158333537Sdes@@ -444,6 +444,9 @@ 159333537Sdes /** minimise QNAME in strict mode, minimise according to RFC. 160333537Sdes * Do not apply fallback */ 161333537Sdes int qname_minimisation_strict; 162333537Sdes+ /** construct fake responses for DNSSEC failures */ 163333537Sdes+ char *redirect_bogus_ipv4; 164333537Sdes+ char *redirect_bogus_ipv6; 165333537Sdes /** SHM data - true if shm is enabled */ 166333537Sdes int shm_enable; 167333537Sdes /** SHM data - key for the shm */ 168333537SdesIndex: util/configlexer.lex 169333537Sdes=================================================================== 170333537Sdes--- util/configlexer.lex (revision 4191) 171333537Sdes+++ util/configlexer.lex (working copy) 172333537Sdes@@ -410,6 +410,8 @@ 173333537Sdes response-ip-tag{COLON} { YDVAR(2, VAR_RESPONSE_IP_TAG) } 174333537Sdes response-ip{COLON} { YDVAR(2, VAR_RESPONSE_IP) } 175333537Sdes response-ip-data{COLON} { YDVAR(2, VAR_RESPONSE_IP_DATA) } 176333537Sdes+redirect-bogus-ipv4{COLON} { YDVAR(1, VAR_REDIRECT_BOGUS_IPV4) } 177333537Sdes+redirect-bogus-ipv6{COLON} { YDVAR(1, VAR_REDIRECT_BOGUS_IPV6) } 178333537Sdes dnscrypt{COLON} { YDVAR(0, VAR_DNSCRYPT) } 179333537Sdes dnscrypt-enable{COLON} { YDVAR(1, VAR_DNSCRYPT_ENABLE) } 180333537Sdes dnscrypt-port{COLON} { YDVAR(1, VAR_DNSCRYPT_PORT) } 181333537SdesIndex: util/configparser.y 182333537Sdes=================================================================== 183333537Sdes--- util/configparser.y (revision 4191) 184333537Sdes+++ util/configparser.y (working copy) 185333537Sdes@@ -44,6 +44,7 @@ 186333537Sdes #include <stdlib.h> 187333537Sdes #include <assert.h> 188333537Sdes 189333537Sdes+#include "sldns/str2wire.h" 190333537Sdes #include "util/configyyrename.h" 191333537Sdes #include "util/config_file.h" 192333537Sdes #include "util/net_help.h" 193333537Sdes@@ -141,6 +142,7 @@ 194333537Sdes %token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW 195333537Sdes %token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1 196333537Sdes %token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING 197333537Sdes+%token VAR_REDIRECT_BOGUS_IPV4 VAR_REDIRECT_BOGUS_IPV6 198333537Sdes %token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY 199333537Sdes %token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER 200333537Sdes %token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT 201333537Sdes@@ -228,6 +230,7 @@ 202333537Sdes server_access_control_tag_data | server_access_control_view | 203333537Sdes server_qname_minimisation_strict | server_serve_expired | 204333537Sdes server_fake_dsa | server_log_identity | server_use_systemd | 205333537Sdes+ server_redirect_bogus_ipv4 | server_redirect_bogus_ipv6 | 206333537Sdes server_response_ip_tag | server_response_ip | server_response_ip_data | 207333537Sdes server_shm_enable | server_shm_key | server_fake_sha1 | 208333537Sdes server_hide_trustanchor | server_trust_anchor_signaling | 209333537Sdes@@ -1873,6 +1876,34 @@ 210333537Sdes #endif 211333537Sdes } 212333537Sdes ; 213333537Sdes+server_redirect_bogus_ipv4: VAR_REDIRECT_BOGUS_IPV4 STRING_ARG 214333537Sdes+ { 215333537Sdes+ uint8_t data[4]; 216333537Sdes+ size_t data_len = 4; 217333537Sdes+ OUTYY(("P(name:%s)\n", $2)); 218333537Sdes+ if(cfg_parser->cfg->redirect_bogus_ipv4) { 219333537Sdes+ yyerror("redirect-bogus-ipv4, can only use one address"); 220333537Sdes+ } 221333537Sdes+ if(sldns_str2wire_a_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) { 222333537Sdes+ yyerror("redirect-bogus-ipv4, not a valid IPv4 address"); 223333537Sdes+ } 224333537Sdes+ free(cfg_parser->cfg->redirect_bogus_ipv4); 225333537Sdes+ cfg_parser->cfg->redirect_bogus_ipv4 = $2; 226333537Sdes+ } 227333537Sdes+server_redirect_bogus_ipv6: VAR_REDIRECT_BOGUS_IPV6 STRING_ARG 228333537Sdes+ { 229333537Sdes+ uint8_t data[16]; 230333537Sdes+ size_t data_len = 16; 231333537Sdes+ OUTYY(("P(name:%s)\n", $2)); 232333537Sdes+ if(cfg_parser->cfg->redirect_bogus_ipv6) { 233333537Sdes+ yyerror("redirect-bogus-ipv6, can only use one address"); 234333537Sdes+ } 235333537Sdes+ if(sldns_str2wire_aaaa_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) { 236333537Sdes+ yyerror("redirect-bogus-ipv6, not a valid IPv6 address"); 237333537Sdes+ } 238333537Sdes+ free(cfg_parser->cfg->redirect_bogus_ipv6); 239333537Sdes+ cfg_parser->cfg->redirect_bogus_ipv6 = $2; 240333537Sdes+ } 241333537Sdes stub_name: VAR_NAME STRING_ARG 242333537Sdes { 243333537Sdes OUTYY(("P(name:%s)\n", $2)); 244333537SdesIndex: util/data/msgencode.c 245333537Sdes=================================================================== 246333537Sdes--- util/data/msgencode.c (revision 4191) 247333537Sdes+++ util/data/msgencode.c (working copy) 248333537Sdes@@ -48,6 +48,7 @@ 249333537Sdes #include "util/regional.h" 250333537Sdes #include "util/net_help.h" 251333537Sdes #include "sldns/sbuffer.h" 252333537Sdes+#include "sldns/str2wire.h" 253333537Sdes #include "services/localzone.h" 254333537Sdes 255333537Sdes /** return code that means the function ran out of memory. negative so it does 256333537Sdes@@ -914,3 +915,63 @@ 257333537Sdes attach_edns_record(buf, &es); 258333537Sdes } 259333537Sdes } 260333537Sdes+ 261333537Sdes+void 262333537Sdes+fixed_address_encode(sldns_buffer* buf, int r, struct query_info* qinfo, 263333537Sdes+ uint16_t qid, uint16_t qflags, struct edns_data* edns, char* data) 264333537Sdes+{ 265333537Sdes+ uint16_t flags; 266333537Sdes+ uint8_t addr_data[16]; 267333537Sdes+ size_t addr_len = 16; 268333537Sdes+ if (qinfo->qtype == LDNS_RR_TYPE_A) { 269333537Sdes+ sldns_str2wire_a_buf(data, addr_data, &addr_len); 270333537Sdes+ } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA) { 271333537Sdes+ sldns_str2wire_aaaa_buf(data, addr_data, &addr_len); 272333537Sdes+ } else { 273333537Sdes+ return error_encode(buf, LDNS_RCODE_NOERROR, qinfo, qid, qflags, edns); 274333537Sdes+ } 275333537Sdes+ sldns_buffer_clear(buf); 276333537Sdes+ sldns_buffer_write(buf, &qid, sizeof(uint16_t)); 277333537Sdes+ flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ 278333537Sdes+ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ 279333537Sdes+ sldns_buffer_write_u16(buf, flags); 280333537Sdes+ if(qinfo) flags = 1; 281333537Sdes+ else flags = 0; 282333537Sdes+ sldns_buffer_write_u16(buf, flags); 283333537Sdes+ sldns_buffer_write_u16(buf, 1); 284333537Sdes+ flags = 0; 285333537Sdes+ sldns_buffer_write(buf, &flags, sizeof(uint16_t)); 286333537Sdes+ sldns_buffer_write(buf, &flags, sizeof(uint16_t)); 287333537Sdes+ if(qinfo) { 288333537Sdes+ // query 289333537Sdes+ if(sldns_buffer_current(buf) == qinfo->qname) 290333537Sdes+ sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); 291333537Sdes+ else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); 292333537Sdes+ sldns_buffer_write_u16(buf, qinfo->qtype); 293333537Sdes+ sldns_buffer_write_u16(buf, qinfo->qclass); 294333537Sdes+ // faked answer 295333537Sdes+ if(sldns_buffer_current(buf) == qinfo->qname) 296333537Sdes+ sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); 297333537Sdes+ else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); 298333537Sdes+ sldns_buffer_write_u16(buf, qinfo->qtype); 299333537Sdes+ sldns_buffer_write_u16(buf, qinfo->qclass); 300333537Sdes+ sldns_buffer_write_u16(buf, 0); 301333537Sdes+ // TTL. Should we make this configurable too? 302333537Sdes+ sldns_buffer_write_u16(buf, 5); 303333537Sdes+ sldns_buffer_write_u16(buf, addr_len); 304333537Sdes+ sldns_buffer_write(buf, addr_data, addr_len); 305333537Sdes+ fflush(stderr); 306333537Sdes+ } 307333537Sdes+ sldns_buffer_flip(buf); 308333537Sdes+ if(edns) { 309333537Sdes+ struct edns_data es = *edns; 310333537Sdes+ es.edns_version = EDNS_ADVERTISED_VERSION; 311333537Sdes+ es.udp_size = EDNS_ADVERTISED_SIZE; 312333537Sdes+ es.ext_rcode = 0; 313333537Sdes+ es.bits &= EDNS_DO; 314333537Sdes+ if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > 315333537Sdes+ edns->udp_size) 316333537Sdes+ return; 317333537Sdes+ attach_edns_record(buf, &es); 318333537Sdes+ } 319333537Sdes+} 320333537SdesIndex: util/data/msgencode.h 321333537Sdes=================================================================== 322333537Sdes--- util/data/msgencode.h (revision 4191) 323333537Sdes+++ util/data/msgencode.h (working copy) 324333537Sdes@@ -128,4 +128,20 @@ 325333537Sdes void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo, 326333537Sdes uint16_t qid, uint16_t qflags, struct edns_data* edns); 327333537Sdes 328333537Sdes+/** 329333537Sdes+ * Encode a fixed address response. 330333537Sdes+ * This is a fake answer to either an A or AAA query 331333537Sdes+ * 332333537Sdes+ * It will answer with that address 333333537Sdes+ * 334333537Sdes+ * @param pkt: where to store the packet. 335333537Sdes+ * @param r: RCODE value to encode. 336333537Sdes+ * @param qinfo: if not NULL, the query is included. 337333537Sdes+ * @param qid: query ID to set in packet. network order. 338333537Sdes+ * @param qflags: original query flags (to copy RD and CD bits). host order. 339333537Sdes+ * @param edns: if not NULL, this is the query edns info, 340333537Sdes+ * and an edns reply is attached. Only attached if EDNS record fits reply. 341333537Sdes+ */ 342333537Sdes+void fixed_address_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo, 343333537Sdes+ uint16_t qid, uint16_t qflags, struct edns_data* edns, char* address); 344333537Sdes #endif /* UTIL_DATA_MSGENCODE_H */ 345