]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Added redirect-bogus.patch to contrib directory.
authorRalph Dolmans <ralph@nlnetlabs.nl>
Fri, 26 May 2017 12:09:38 +0000 (12:09 +0000)
committerRalph Dolmans <ralph@nlnetlabs.nl>
Fri, 26 May 2017 12:09:38 +0000 (12:09 +0000)
git-svn-id: file:///svn/unbound/trunk@4194 be551aaa-1e26-0410-a405-d3ace91eadb9

contrib/README
contrib/redirect-bogus.patch [new file with mode: 0644]
doc/Changelog

index 7ccae735d79712cee08cebf847ab79e832df0ff7..ea3d2846d524c62f1d3a4652c6fd4daabaaa46aa 100644 (file)
@@ -31,3 +31,5 @@ distribution but may be helpful.
   Contributed by Yuri Voinov.
 * unbound.socket and unbound.service: systemd files for unbound, install them
   in /usr/lib/systemd/system.  Contributed by Sami Kerola and Pavel Odintsov.
+* redirect-bogus.patch: Return configured address for bogus A and AAAA answers,
+  instead of SERVFAIL. Contributed by SIDN.
diff --git a/contrib/redirect-bogus.patch b/contrib/redirect-bogus.patch
new file mode 100644 (file)
index 0000000..8f8035c
--- /dev/null
@@ -0,0 +1,344 @@
+Index: daemon/worker.c
+===================================================================
+--- daemon/worker.c    (revision 4191)
++++ daemon/worker.c    (working copy)
+@@ -663,8 +663,21 @@
+               if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
+                       LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+                       goto bail_out;
+-              error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
+-                      qinfo, id, flags, edns);
++              if (qinfo->qtype == LDNS_RR_TYPE_A &&
++                      worker->env.cfg->redirect_bogus_ipv4) {
++                      /* BAD cached */
++                      fixed_address_encode(repinfo->c->buffer,
++                              LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
++                              worker->env.cfg->redirect_bogus_ipv4);
++              } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA &&
++                      worker->env.cfg->redirect_bogus_ipv6) {
++                      fixed_address_encode(repinfo->c->buffer,
++                              LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
++                              worker->env.cfg->redirect_bogus_ipv6);
++              } else {
++                      error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
++                      qinfo, id, flags, edns);
++              }
+               rrset_array_unlock_touch(worker->env.rrset_cache, 
+                       worker->scratchpad, rep->ref, rep->rrset_count);
+               if(worker->stats.extended) {
+Index: doc/unbound.conf.5.in
+===================================================================
+--- doc/unbound.conf.5.in      (revision 4191)
++++ doc/unbound.conf.5.in      (working copy)
+@@ -1244,6 +1244,18 @@
+ This can make ordinary queries complete (if repeatedly queried for),
+ and enter the cache, whilst also mitigating the traffic flow by the
+ factor given.
++.TP 5
++.B redirect-bogus-ipv4: \fI<IPv4 address>
++Set a fixed address for DNSSEC failures that are cached
++Instead of responding to A queries with SERVFAIL, respond
++with NOERROR and the address specified here
++The TTL of the response will be 5 seconds
++.TP 5
++.B redirect-bogus-ipv6: \fI<IPv4 address>
++Set a fixed address for DNSSEC failures that are cached
++Instead of responding to AAAA queries with SERVFAIL, respond
++with NOERROR and the address specified here
++The TTL of the response will be 5 seconds
+ .SS "Remote Control Options"
+ In the
+ .B remote\-control:
+Index: services/mesh.c
+===================================================================
+--- services/mesh.c    (revision 4191)
++++ services/mesh.c    (working copy)
+@@ -1006,6 +1006,7 @@
+       struct timeval end_time;
+       struct timeval duration;
+       int secure;
++      int bogus_override = 0;
+       /* Copy the client's EDNS for later restore, to make sure the edns
+        * compare is with the correct edns options. */
+       struct edns_data edns_bak = r->edns;
+@@ -1016,6 +1017,7 @@
+               rcode = LDNS_RCODE_SERVFAIL;
+               if(m->s.env->cfg->stat_extended) 
+                       m->s.env->mesh->ans_bogus++;
++              bogus_override = 1;
+       }
+       if(rep && rep->security == sec_status_secure)
+               secure = 1;
+@@ -1047,17 +1049,34 @@
+       } else if(rcode) {
+               m->s.qinfo.qname = r->qname;
+               m->s.qinfo.local_alias = r->local_alias;
+-              if(rcode == LDNS_RCODE_SERVFAIL) {
+-                      if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
+-                              rep, rcode, &r->edns, m->s.region))
+-                                      r->edns.opt_list = NULL;
+-              } else { 
+-                      if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
+-                              &r->edns, m->s.region))
+-                                      r->edns.opt_list = NULL;
++              if(bogus_override && m->s.qinfo.qtype == LDNS_RR_TYPE_A &&
++                      m->s.env->cfg->redirect_bogus_ipv4) {
++                      fixed_address_encode(r->query_reply.c->buffer,
++                              LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
++                              r->qflags, &r->edns,
++                              m->s.env->cfg->redirect_bogus_ipv4);
++              } else if(bogus_override &&
++                      m->s.qinfo.qtype == LDNS_RR_TYPE_AAAA &&
++                      m->s.env->cfg->redirect_bogus_ipv6) {
++                      fixed_address_encode(r->query_reply.c->buffer,
++                              LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
++                              r->qflags, &r->edns,
++                              m->s.env->cfg->redirect_bogus_ipv6);
++              } else {
++                      if(rcode == LDNS_RCODE_SERVFAIL) {
++                              if(!inplace_cb_reply_servfail_call(m->s.env,
++                                      &m->s.qinfo, &m->s,
++                                      rep, rcode, &r->edns, m->s.region))
++                                              r->edns.opt_list = NULL;
++                      } else { 
++                              if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo,
++                                      &m->s, rep, rcode, &r->edns,
++                                      m->s.region))
++                                              r->edns.opt_list = NULL;
++                      }
++                      error_encode(r->query_reply.c->buffer, rcode,
++                              &m->s.qinfo, r->qid, r->qflags, &r->edns);
+               }
+-              error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
+-                      r->qid, r->qflags, &r->edns);
+               comm_point_send_reply(&r->query_reply);
+       } else {
+               size_t udp_size = r->edns.udp_size;
+Index: util/config_file.c
+===================================================================
+--- util/config_file.c (revision 4191)
++++ util/config_file.c (working copy)
+@@ -273,6 +273,8 @@
+       cfg->ratelimit_factor = 10;
+       cfg->qname_minimisation = 0;
+       cfg->qname_minimisation_strict = 0;
++      cfg->redirect_bogus_ipv4 = NULL;
++      cfg->redirect_bogus_ipv6 = NULL;
+       cfg->shm_enable = 0;
+       cfg->shm_key = 11777;
+       cfg->dnscrypt = 0;
+@@ -602,6 +604,10 @@
+               }
+               oi[cfg->num_out_ifs++] = d;
+               cfg->out_ifs = oi;
++      } else if (strcmp(opt, "redirect-bogus-ipv4:") == 0) {
++              cfg->redirect_bogus_ipv4 = strdup(val);
++      } else if (strcmp(opt, "redirect-bogus-ipv6:") == 0) {
++              cfg->redirect_bogus_ipv6 = strdup(val);
+       } else {
+               /* unknown or unsupported (from the set_option interface):
+                * interface, outgoing-interface, access-control,
+@@ -1250,6 +1256,12 @@
+       free(cfg->dnstap_version);
+       config_deldblstrlist(cfg->ratelimit_for_domain);
+       config_deldblstrlist(cfg->ratelimit_below_domain);
++      if (cfg->redirect_bogus_ipv4) {
++              free(cfg->redirect_bogus_ipv4);
++      }
++      if (cfg->redirect_bogus_ipv6) {
++              free(cfg->redirect_bogus_ipv6);
++      }
+ #ifdef USE_IPSECMOD
+       free(cfg->ipsecmod_hook);
+       config_delstrlist(cfg->ipsecmod_whitelist);
+Index: util/config_file.h
+===================================================================
+--- util/config_file.h (revision 4191)
++++ util/config_file.h (working copy)
+@@ -444,6 +444,9 @@
+       /** minimise QNAME in strict mode, minimise according to RFC.
+        *  Do not apply fallback */
+       int qname_minimisation_strict;
++      /** construct fake responses for DNSSEC failures */
++      char *redirect_bogus_ipv4;
++      char *redirect_bogus_ipv6;
+       /** SHM data - true if shm is enabled */
+       int shm_enable;
+       /** SHM data - key for the shm */
+Index: util/configlexer.lex
+===================================================================
+--- util/configlexer.lex       (revision 4191)
++++ util/configlexer.lex       (working copy)
+@@ -410,6 +410,8 @@
+ response-ip-tag{COLON}                { YDVAR(2, VAR_RESPONSE_IP_TAG) }
+ response-ip{COLON}            { YDVAR(2, VAR_RESPONSE_IP) }
+ response-ip-data{COLON}               { YDVAR(2, VAR_RESPONSE_IP_DATA) }
++redirect-bogus-ipv4{COLON}    { YDVAR(1, VAR_REDIRECT_BOGUS_IPV4) }
++redirect-bogus-ipv6{COLON}    { YDVAR(1, VAR_REDIRECT_BOGUS_IPV6) }
+ dnscrypt{COLON}                       { YDVAR(0, VAR_DNSCRYPT) }
+ dnscrypt-enable{COLON}                { YDVAR(1, VAR_DNSCRYPT_ENABLE) }
+ dnscrypt-port{COLON}          { YDVAR(1, VAR_DNSCRYPT_PORT) }
+Index: util/configparser.y
+===================================================================
+--- util/configparser.y        (revision 4191)
++++ util/configparser.y        (working copy)
+@@ -44,6 +44,7 @@
+ #include <stdlib.h>
+ #include <assert.h>
++#include "sldns/str2wire.h"
+ #include "util/configyyrename.h"
+ #include "util/config_file.h"
+ #include "util/net_help.h"
+@@ -141,6 +142,7 @@
+ %token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
+ %token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1
+ %token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
++%token VAR_REDIRECT_BOGUS_IPV4 VAR_REDIRECT_BOGUS_IPV6
+ %token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
+ %token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
+ %token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
+@@ -228,6 +230,7 @@
+       server_access_control_tag_data | server_access_control_view |
+       server_qname_minimisation_strict | server_serve_expired |
+       server_fake_dsa | server_log_identity | server_use_systemd |
++      server_redirect_bogus_ipv4 | server_redirect_bogus_ipv6 |
+       server_response_ip_tag | server_response_ip | server_response_ip_data |
+       server_shm_enable | server_shm_key | server_fake_sha1 |
+       server_hide_trustanchor | server_trust_anchor_signaling |
+@@ -1873,6 +1876,34 @@
+       #endif
+       }
+       ;
++server_redirect_bogus_ipv4: VAR_REDIRECT_BOGUS_IPV4 STRING_ARG
++      {
++              uint8_t data[4];
++              size_t data_len = 4;
++              OUTYY(("P(name:%s)\n", $2));
++              if(cfg_parser->cfg->redirect_bogus_ipv4) {
++                      yyerror("redirect-bogus-ipv4, can only use one address");
++              }
++              if(sldns_str2wire_a_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
++                      yyerror("redirect-bogus-ipv4, not a valid IPv4 address");
++              }
++              free(cfg_parser->cfg->redirect_bogus_ipv4);
++              cfg_parser->cfg->redirect_bogus_ipv4 = $2;
++      }
++server_redirect_bogus_ipv6: VAR_REDIRECT_BOGUS_IPV6 STRING_ARG
++      {
++              uint8_t data[16];
++              size_t data_len = 16;
++              OUTYY(("P(name:%s)\n", $2));
++              if(cfg_parser->cfg->redirect_bogus_ipv6) {
++                      yyerror("redirect-bogus-ipv6, can only use one address");
++              }
++              if(sldns_str2wire_aaaa_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
++                      yyerror("redirect-bogus-ipv6, not a valid IPv6 address");
++              }
++              free(cfg_parser->cfg->redirect_bogus_ipv6);
++              cfg_parser->cfg->redirect_bogus_ipv6 = $2;
++      }
+ stub_name: VAR_NAME STRING_ARG
+       {
+               OUTYY(("P(name:%s)\n", $2));
+Index: util/data/msgencode.c
+===================================================================
+--- util/data/msgencode.c      (revision 4191)
++++ util/data/msgencode.c      (working copy)
+@@ -48,6 +48,7 @@
+ #include "util/regional.h"
+ #include "util/net_help.h"
+ #include "sldns/sbuffer.h"
++#include "sldns/str2wire.h"
+ #include "services/localzone.h"
+ /** return code that means the function ran out of memory. negative so it does
+@@ -914,3 +915,63 @@
+               attach_edns_record(buf, &es);
+       }
+ }
++
++void 
++fixed_address_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
++      uint16_t qid, uint16_t qflags, struct edns_data* edns, char* data)
++{
++      uint16_t flags;
++      uint8_t addr_data[16];
++      size_t addr_len = 16;
++      if (qinfo->qtype == LDNS_RR_TYPE_A) {
++              sldns_str2wire_a_buf(data, addr_data, &addr_len);
++      } else if (qinfo->qtype == LDNS_RR_TYPE_AAAA) {
++              sldns_str2wire_aaaa_buf(data, addr_data, &addr_len);
++      } else {
++              return error_encode(buf, LDNS_RCODE_NOERROR, qinfo, qid, qflags, edns);
++      }
++      sldns_buffer_clear(buf);
++      sldns_buffer_write(buf, &qid, sizeof(uint16_t));
++      flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
++      flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
++      sldns_buffer_write_u16(buf, flags);
++      if(qinfo) flags = 1;
++      else    flags = 0;
++      sldns_buffer_write_u16(buf, flags);
++      sldns_buffer_write_u16(buf, 1);
++      flags = 0;
++      sldns_buffer_write(buf, &flags, sizeof(uint16_t));
++      sldns_buffer_write(buf, &flags, sizeof(uint16_t));
++      if(qinfo) {
++              // query
++              if(sldns_buffer_current(buf) == qinfo->qname)
++                      sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
++              else    sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
++              sldns_buffer_write_u16(buf, qinfo->qtype);
++              sldns_buffer_write_u16(buf, qinfo->qclass);
++              // faked answer
++              if(sldns_buffer_current(buf) == qinfo->qname)
++                      sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
++              else    sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
++              sldns_buffer_write_u16(buf, qinfo->qtype);
++              sldns_buffer_write_u16(buf, qinfo->qclass);
++              sldns_buffer_write_u16(buf, 0);
++              // TTL. Should we make this configurable too?
++              sldns_buffer_write_u16(buf, 5);
++              sldns_buffer_write_u16(buf, addr_len);
++              sldns_buffer_write(buf, addr_data, addr_len);
++              fflush(stderr);
++      }
++      sldns_buffer_flip(buf);
++      if(edns) {
++              struct edns_data es = *edns;
++              es.edns_version = EDNS_ADVERTISED_VERSION;
++              es.udp_size = EDNS_ADVERTISED_SIZE;
++              es.ext_rcode = 0;
++              es.bits &= EDNS_DO;
++              if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
++                      edns->udp_size)
++                      return;
++              attach_edns_record(buf, &es);
++      }
++}
+Index: util/data/msgencode.h
+===================================================================
+--- util/data/msgencode.h      (revision 4191)
++++ util/data/msgencode.h      (working copy)
+@@ -128,4 +128,20 @@
+ void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
+       uint16_t qid, uint16_t qflags, struct edns_data* edns);
++/**
++ * Encode a fixed address response.
++ * This is a fake answer to either an A or AAA query
++ *
++ * It will answer with that address
++ *
++ * @param pkt: where to store the packet.
++ * @param r: RCODE value to encode.
++ * @param qinfo: if not NULL, the query is included.
++ * @param qid: query ID to set in packet. network order.
++ * @param qflags: original query flags (to copy RD and CD bits). host order.
++ * @param edns: if not NULL, this is the query edns info,
++ *    and an edns reply is attached. Only attached if EDNS record fits reply.
++ */
++void fixed_address_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
++      uint16_t qid, uint16_t qflags, struct edns_data* edns, char* address);
+ #endif /* UTIL_DATA_MSGENCODE_H */
index fdbcf4b6ec0e1ae383101c37fe63af25de4cbe0e..e27214c651cf6ae9c3ec211fa20a326c1d68b047 100644 (file)
@@ -1,3 +1,6 @@
+26 May 2017: Ralph
+       - Added redirect-bogus.patch to contrib directory.
+
 26 May 2017: Wouter
        - Fix #1270: unitauth.c doesn't compile with higher warning level
          and optimization