]> git.ipfire.org Git - people/ms/dnsmasq.git/blobdiff - src/forward.c
Tweak EDNS timeout code.
[people/ms/dnsmasq.git] / src / forward.c
index e8cf615aa9399367725667a01d45fba6442bd78d..74e5ab66c423a9d09f48c9cab7a82f258de3576a 100644 (file)
@@ -253,6 +253,7 @@ 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;
 
@@ -261,19 +262,32 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
     forward = NULL;
   else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
     {
+      /* If we didn't get an answer advertising a maximal packet in EDNS,
+        fall back to 1280, which should work everywhere on IPv6.
+        If that generates an answer, it will become the new default
+        for this server */
+      forward->flags |= FREC_TEST_PKTSZ;
+      
 #ifdef HAVE_DNSSEC
       /* If we've already got an answer to this query, but we're awaiting keys for validation,
         there's no point retrying the query, retry the key query instead...... */
       if (forward->blocking_query)
        {
          int fd;
-
+         
+         forward->flags &= ~FREC_TEST_PKTSZ;
+         
          while (forward->blocking_query)
            forward = forward->blocking_query;
+          
+         forward->flags |= FREC_TEST_PKTSZ;
          
          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 (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");
 #ifdef HAVE_IPV6
@@ -417,7 +431,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
          plen = new_plen;
        }
 #endif
-
+      
       while (1)
        { 
          /* only send to servers dealing with our domain.
@@ -464,6 +478,9 @@ 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);
              
              if (retry_send(sendto(fd, (char *)header, plen, 0,
                                    &start->addr.sa,
@@ -530,7 +547,8 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
   size_t plen; 
 
   (void)ad_reqd;
-  (void) do_bit;
+  (void)do_bit;
+  (void)bogusanswer;
 
 #ifdef HAVE_IPSET
   if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
@@ -759,7 +777,6 @@ void reply_query(int fd, int family, time_t now)
     }   
    
   server = forward->sentto;
-  
   if ((forward->sentto->flags & SERV_TYPE) == 0)
     {
       if (RCODE(header) == REFUSED)
@@ -780,7 +797,14 @@ void reply_query(int fd, int family, time_t now)
       if (!option_bool(OPT_ALL_SERVERS))
        daemon->last_server = server;
     }
-
+  /* We tried resending to this server with a smaller maximum size and got an answer.
+     Make that permanent. To avoid reduxing the packet size for an single dropped packet,
+     only do this when we get a truncated answer, or one larger than the safe size. */
+  if (server && (forward->flags & FREC_TEST_PKTSZ) && 
+      ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
+    server->edns_pktsz = SAFE_PKTSZ;
+  
   /* If the answer is an error, keep the forward record in place in case
      we get a good reply from another server. Kill it when we've
      had replies from all to avoid filling the forwarding table when
@@ -889,7 +913,7 @@ void reply_query(int fd, int family, time_t now)
                    {
                      new->flags |= FREC_DNSKEY_QUERY; 
                      nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
-                                                daemon->keyname, forward->class, T_DNSKEY, &server->addr);
+                                                daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
                    }
                  else 
                    {
@@ -898,7 +922,7 @@ void reply_query(int fd, int family, time_t now)
                      else
                        new->flags |= FREC_DS_QUERY;
                      nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
-                                                daemon->keyname, forward->class, T_DS, &server->addr);
+                                                daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
                    }
                  if ((hash = hash_questions(header, nn, daemon->namebuff)))
                    memcpy(new->hash, hash, HASH_SIZE);
@@ -1013,7 +1037,7 @@ void reply_query(int fd, int family, time_t now)
            header->hb3 |= HB3_TC;
          else
            {
-             char *result;
+             char *result, *domain = "result";
              
              if (forward->work_counter == 0)
                {
@@ -1023,7 +1047,10 @@ void reply_query(int fd, int family, time_t now)
              else
                result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
              
-             log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
+             if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
+               domain = daemon->namebuff;
+
+             log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
            }
          
          if (status == STAT_SECURE)
@@ -1522,7 +1549,7 @@ static int  tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
       
       /* Can't find it in the cache, have to send a query */
 
-      m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr);
+      m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr, server->edns_pktsz);
       
       *length = htons(m);
       
@@ -1634,7 +1661,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
 
     another_tcp_key:
       m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class, 
-                               new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr);
+                               new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
       
       *length = htons(m);
       
@@ -1974,7 +2001,7 @@ unsigned char *tcp_request(int confd, time_t now,
                        {
                          int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
                          int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
-                         char *result;
+                         char *result, *domain = "result";
 
                          if (status == STAT_INSECURE_DS)
                            {
@@ -1993,7 +2020,10 @@ unsigned char *tcp_request(int confd, time_t now,
                          else
                            result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
                          
-                         log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
+                         if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
+                           domain = daemon->namebuff;
+
+                         log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
                          
                          if (status == STAT_BOGUS)
                            {
@@ -2034,8 +2064,8 @@ unsigned char *tcp_request(int confd, time_t now,
 #endif
 
                      m = process_reply(header, now, last_server, (unsigned int)m, 
-                                       option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, bogusanswer,
-                                       cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
+                                       option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
+                                       ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
                      
                      break;
                    }