]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
Major tidy up of EDNS0 handling and computation/use of udp packet size.
authorSimon Kelley <simon@thekelleys.org.uk>
Sun, 20 Dec 2015 17:12:16 +0000 (17:12 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Sun, 20 Dec 2015 17:12:16 +0000 (17:12 +0000)
src/auth.c
src/dnsmasq.h
src/dnssec.c
src/forward.c
src/netlink.c
src/rfc1035.c
src/rrfilter.c

index 2b0b7d6b052df410804b436df4354432438ab079..85bd5e7d6338525fba1c4dbeb075ef4e10d34434 100644 (file)
@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
 }
 
 
-size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) 
+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, 
+                  int local_query, int do_bit, int have_pseudoheader) 
 {
   char *name = daemon->namebuff;
   unsigned char *p, *ansp;
@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
   header->ancount = htons(anscount);
   header->nscount = htons(authcount);
   header->arcount = htons(0);
+
+  /* Advertise our packet size limit in our reply */
+  if (have_pseudoheader)
+    return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
+
   return ansp - (unsigned char *)header;
 }
   
index 39a930c9abaf3932ff5dc639d5d2779c823a177e..abb34c5193b658242e2abd713d70d9e2c74b9f4e 100644 (file)
@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
                      int no_cache, int secure, int *doctored);
 size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
                      struct in_addr local_addr, struct in_addr local_netmask, 
-                     time_t now, int *ad_reqd, int *do_bit);
+                     time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
 int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
                             struct bogus_addr *addr, time_t now);
 int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now);
 unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
 size_t resize_packet(struct dns_header *header, size_t plen, 
                  unsigned char *pheader, size_t hlen);
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
+                       unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
 size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
 size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
 #ifdef HAVE_DNSSEC
@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost);
 /* auth.c */
 #ifdef HAVE_AUTH
 size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, 
-                  time_t now, union mysockaddr *peer_addr, int local_query);
+                  time_t now, union mysockaddr *peer_addr, int local_query,
+                  int do_bit, int have_pseudoheader);
 int in_zone(struct auth_zone *zone, char *name, char **cut);
 #endif
 
index 82394eeddb93a9f4b859dd2e57be7d41e21177ee..299ca64d5d7f0c4a56a60398dd94337fd91322f4 100644 (file)
@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo)
     case 12: return "gosthash94";
     case 13: return "sha256";
     case 14: return "sha384";
-
     default: return NULL;
     }
 }
index 3e801c86045fce43029c8c307d36b7f1bd35f095..041353c37c8227924f2577e7e0afd213daf81639 100644 (file)
@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
   void *hash = &crc;
 #endif
  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
- unsigned char *pheader;
 
  (void)do_bit;
 
@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
         there's no point retrying the query, retry the key query instead...... */
       if (forward->blocking_query)
        {
-         int fd;
+         int fd, is_sign;
+         unsigned char *pheader;
          
          forward->flags &= ~FREC_TEST_PKTSZ;
          
@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
          blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
          plen = forward->stash_len;
          
-         if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
-           PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
+         if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
+           PUTSHORT(SAFE_PKTSZ, pheader);
 
          if (forward->sentto->addr.sa.sa_family == AF_INET) 
            log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
       forward->log_id = daemon->log_id;
       
       if (option_bool(OPT_ADD_MAC))
-       plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
-      
+       {
+         size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
+         if (new != plen)
+           {
+             plen = new;
+             forward->flags |= FREC_ADDED_PHEADER;
+           }
+       }
+
       if (option_bool(OPT_CLIENT_SUBNET))
        {
          size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); 
          if (new != plen)
            {
              plen = new;
-             forward->flags |= FREC_HAS_SUBNET;
+             forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
            }
        }
 
 #ifdef HAVE_DNSSEC
       if (option_bool(OPT_DNSSEC_VALID))
        {
-         size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
+         size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
         
+         if (new != plen)
+           forward->flags |= FREC_ADDED_PHEADER;
+
+         plen = new;
+             
          /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
             this allows it to select auth servers when one is returning bad data. */
          if (option_bool(OPT_DNSSEC_DEBUG))
            header->hb4 |= HB4_CD;
 
-         if (new_plen != plen)
-           forward->flags |= FREC_ADDED_PHEADER;
-
-         plen = new_plen;
        }
 #endif
       
@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
                    }
 #endif
                }
-
-             if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
-               PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
              
+#ifdef HAVE_DNSSEC
+             if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
+               {
+                 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
+                    packet size to 512. But that won't provide space for the RRSIGS in many cases.
+                    The RRSIGS will be stripped out before the answer goes back, so the packet should
+                    shrink again. So, if we added a do-bit, bump the udp packet size to the value
+                    known to be OK for this server. Maybe check returned size after stripping and set
+                    the truncated bit? */                
+                 unsigned char *pheader;
+                 int is_sign;
+                 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
+                   PUTSHORT(start->edns_pktsz, pheader);
+               }
+#endif
+
              if (retry_send(sendto(fd, (char *)header, plen, 0,
                                    &start->addr.sa,
                                    sa_len(&start->addr))))
@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
     }
 #endif
   
-  /* If upstream is advertising a larger UDP packet size
-     than we allow, trim it so that we don't get overlarge
-     requests for the client. We can't do this for signed packets. */
-
   if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
     {
-      unsigned short udpsz;
-      unsigned char *psave = sizep;
-      
-      GETSHORT(udpsz, sizep);
-
-      if (!is_sign && udpsz > daemon->edns_pktsz)
-       PUTSHORT(daemon->edns_pktsz, psave);
-      
       if (check_subnet && !check_source(header, plen, pheader, query_source))
        {
          my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
          return 0;
        }
       
-      if (added_pheader)
+      if (!is_sign)
        {
-         pheader = 0; 
-         header->arcount = htons(0);
+         if (added_pheader)
+           {
+             /* client didn't send EDNS0, we added one, strip it off before returning answer. */
+             n = rrfilter(header, n, 0);
+             pheader = NULL;
+           }
+         else
+           {
+             /* If upstream is advertising a larger UDP packet size
+                than we allow, trim it so that we don't get overlarge
+                requests for the client. We can't do this for signed packets. */
+             unsigned short udpsz;
+             unsigned char *psave = sizep;
+             
+             GETSHORT(udpsz, sizep);
+             if (udpsz > daemon->edns_pktsz)
+               PUTSHORT(daemon->edns_pktsz, psave);
+           }
        }
     }
   
@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
     }
 
   if (option_bool(OPT_DNSSEC_VALID))
-    header->hb4 &= ~HB4_AD;
-  
-  if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
-    header->hb4 |= HB4_AD;
-
-  /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
-  if (!do_bit)
-    n = rrfilter(header, n, 1);
+    {
+      header->hb4 &= ~HB4_AD;
+      
+      if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
+       header->hb4 |= HB4_AD;
+      
+      /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
+      if (!do_bit)
+       n = rrfilter(header, n, 1);
+    }
 #endif
 
   /* do this after extract_addresses. Ensure NODATA reply and remove
@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now)
          if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
            {
              header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
-             header->hb4 &= ~(HB4_RA | HB4_RCODE);
-             forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
+             header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
+             if (forward->flags |= FREC_CHECKING_DISABLED)
+               header->hb4 |= HB4_CD;
+             if (forward->flags |= FREC_AD_QUESTION)
+               header->hb4 |= HB4_AD;
+             if (forward->flags & FREC_DO_QUESTION)
+               add_do_bit(header, nn,  (char *)pheader + plen);
+             forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
              return;
            }
        }
@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now)
 {
   struct dns_header *header = (struct dns_header *)daemon->packet;
   union mysockaddr source_addr;
-  unsigned short type;
+  unsigned char *pheader;
+  unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
   struct all_addr dst_addr;
   struct in_addr netmask, dst_addr_4;
   size_t m;
   ssize_t n;
-  int if_index = 0, auth_dns = 0;
+  int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
 #ifdef HAVE_AUTH
   int local_auth = 0;
 #endif
@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now)
 #endif
     }
   
+  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
+    { 
+      unsigned short flags;
+      
+      have_pseudoheader = 1;
+      GETSHORT(udp_size, pheader);
+      pheader += 2; /* ext_rcode */
+      GETSHORT(flags, pheader);
+      
+      if (flags & 0x8000)
+       do_bit = 1;/* do bit */ 
+       
+      /* If the client provides an EDNS0 UDP size, use that to limit our reply.
+        (bounded by the maximum configured). If no EDNS0, then it
+        defaults to 512 */
+      if (udp_size > daemon->edns_pktsz)
+       udp_size = daemon->edns_pktsz;
+    }
+
 #ifdef HAVE_AUTH
   if (auth_dns)
     {
-      m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth);
+      m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, 
+                     local_auth, do_bit, have_pseudoheader);
       if (m >= 1)
        {
          send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now)
   else
 #endif
     {
-      int ad_reqd, do_bit;
-      m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, 
-                        dst_addr_4, netmask, now, &ad_reqd, &do_bit);
+      int ad_reqd = do_bit;
+       /* RFC 6840 5.7 */
+      if (header->hb4 & HB4_AD)
+       ad_reqd = 1;
+
+      m = answer_request(header, ((char *) header) + udp_size, (size_t)n, 
+                        dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
       
       if (m >= 1)
        {
@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now,
 #ifdef HAVE_AUTH
   int local_auth = 0;
 #endif
-  int checking_disabled, ad_question, do_bit, added_pheader = 0;
+  int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
   int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
   size_t m;
   unsigned short qtype;
@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now,
   union mysockaddr peer_addr;
   socklen_t peer_len = sizeof(union mysockaddr);
   int query_count = 0;
+  unsigned char *pheader;
 
   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
     return packet;
@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now,
       else
        dst_addr_4.s_addr = 0;
       
+      do_bit = 0;
+
+      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
+       { 
+         unsigned short flags;
+         
+         have_pseudoheader = 1;
+         pheader += 4; /* udp_size, ext_rcode */
+         GETSHORT(flags, pheader);
+      
+         if (flags & 0x8000)
+           do_bit = 1;/* do bit */ 
+       }
+
 #ifdef HAVE_AUTH
       if (auth_dns)
-       m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
+       m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, 
+                       local_auth, do_bit, have_pseudoheader);
       else
 #endif
        {
-         /* m > 0 if answered from cache */
-         m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
-                            dst_addr_4, netmask, now, &ad_question, &do_bit);
+          int ad_reqd = do_bit;
+          /* RFC 6840 5.7 */
+          if (header->hb4 & HB4_AD)
+            ad_reqd = 1;
+          
+          /* m > 0 if answered from cache */
+          m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
+                             dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
          
          /* Do this by steam now we're not in the select() loop */
          check_log_writer(1); 
@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now,
                            }
                          
 #ifdef HAVE_DNSSEC
+                         added_pheader = 0;                      
                          if (option_bool(OPT_DNSSEC_VALID))
                            {
                              size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now,
 
                      m = process_reply(header, now, last_server, (unsigned int)m, 
                                        option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
-                                       ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
+                                       ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); 
                      
                      break;
                    }
index 753784dc20b44f83529b3c0eae472c280433fc71..3376d680bd2ec5d19bf30825e906a0844f4169e2 100644 (file)
@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
                rta = RTA_NEXT(rta, len1);
              }
 
-           if (inaddr && mac && callback_ok)
+           if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
+               inaddr && mac && callback_ok)
              if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
                callback_ok = 0;
          }
index 188d05f17b9983e789b8f98a09b6116c1b52b8b5..18858a8fcb3e365c52311d29be892ae5bf8c4d48 100644 (file)
@@ -489,8 +489,8 @@ struct macparm {
   union mysockaddr *l3;
 };
  
-static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
-                              int optno, unsigned char *opt, size_t optlen, int set_do)
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
+                       unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
 { 
   unsigned char *lenp, *datap, *p;
   int rdlen, is_sign;
@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
        return plen;
       *p++ = 0; /* empty name */
       PUTSHORT(T_OPT, p);
-      PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
+      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
       PUTSHORT(0, p);    /* extended RCODE and version */
       PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
       lenp = p;
@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
   if (!match)
     return 1; /* continue */
 
-  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit,  EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
+  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
   
   return 0; /* done */
 }            
@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
 {
   struct macparm parm;
      
-/* Must have an existing pseudoheader as the only ar-record, 
-   or have no ar-records. Must also not be signed */
-   
-  if (ntohs(header->arcount) > 1)
-    return plen;
-
   parm.header = header;
   parm.limit = (unsigned char *)limit;
   parm.plen = plen;
@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
   struct subnet_opt opt;
   
   len = calc_subnet_opt(&opt, source);
-  return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
 }
 
 #ifdef HAVE_DNSSEC
 size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
 {
-  return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
+  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
 }
 #endif
 
@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
 /* return zero if we can't answer from cache, or packet size if we can */
 size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
                      struct in_addr local_addr, struct in_addr local_netmask, 
-                     time_t now, int *ad_reqd, int *do_bit
+                     time_t now, int ad_reqd, int do_bit, int have_pseudoheader
 {
   char *name = daemon->namebuff;
-  unsigned char *p, *ansp, *pheader;
+  unsigned char *p, *ansp;
   unsigned int qtype, qclass;
   struct all_addr addr;
   int nameoffset;
   unsigned short flag;
   int q, ans, anscount = 0, addncount = 0;
-  int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
+  int dryrun = 0;
   struct crec *crecp;
   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
   struct mx_srv_record *rec;
@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
   if (header->hb4 & HB4_CD)
     sec_data = 0;
   
-  /* RFC 6840 5.7 */
-  *ad_reqd = header->hb4 & HB4_AD;
-  *do_bit = 0;
-
   /* If there is an  additional data section then it will be overwritten by
      partial replies, so we have to do a dry run to see if we can answer
      the query. */
-
   if (ntohs(header->arcount) != 0)
-    {
-      dryrun = 1;
-
-      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
-      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
-       { 
-         unsigned short flags;
-         
-         have_pseudoheader = 1;
-         
-         pheader += 4; /* udp size, ext_rcode */
-         GETSHORT(flags, pheader);
-         
-         if ((sec_reqd = flags & 0x8000))
-           {
-             *do_bit = 1;/* do bit */ 
-             *ad_reqd = 1;
-           }
-       }
-    }
+    dryrun = 1;
 
   for (rec = daemon->mxnames; rec; rec = rec->next)
     rec->offset = 0;
@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
       GETSHORT(qtype, p); 
       GETSHORT(qclass, p);
 
-      /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
-        not set. */
-      if (qtype == T_ANY)
-       *do_bit = 1;
-
       ans = 0; /* have we answered this question */
       
       if (qtype == T_TXT || qtype == T_ANY)
@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                     the zone is unsigned, which implies that we're doing
                     validation. */
                  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
-                     !sec_reqd || 
+                     !do_bit || 
                      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
                    {
                      do 
@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                    }
 
                  /* If the client asked for DNSSEC  don't use cached data. */
-                 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
+                 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
                    do
                      { 
                        /* don't answer wildcard queries with data not from /etc/hosts
@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                        
                        if (crecp->flags & F_NEG)
                          {
-                           /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
-                              is cached and the client wants DNSSEC, forward rather than answering from the cache */
-                           if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
-                             {
-                               ans = 1;
-                               auth = 0;
-                               if (crecp->flags & F_NXDOMAIN)
-                                 nxdomain = 1;
-                               if (!dryrun)
-                                 log_query(crecp->flags, name, NULL, NULL);
-                             }
+                           ans = 1;
+                           auth = 0;
+                           if (crecp->flags & F_NXDOMAIN)
+                             nxdomain = 1;
+                           if (!dryrun)
+                             log_query(crecp->flags, name, NULL, NULL);
                          }
                        else 
                          {
@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 
   len = ansp - (unsigned char *)header;
   
+  /* Advertise our packet size limit in our reply */
   if (have_pseudoheader)
-    len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
+    len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
   
-  if (*ad_reqd && sec_data)
+  if (ad_reqd && sec_data)
     header->hb4 |= HB4_AD;
   else
     header->hb4 &= ~HB4_AD;
index ae122619729227b473a9be6653911f9a1539d38a..b26b39f06be3a64630d9264f151ebc644e78370a 100644 (file)
@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
   for (p = rrs[0], i = 1; i < rr_found; i += 2)
     {
       unsigned char *start = rrs[i];
-      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
+      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
       
       memmove(p, start, end-start);
       p += end-start;