"Fossies" - the Fresh Open Source Software Archive

Member "nsd-4.3.6/axfr.c" (6 Apr 2021, 6273 Bytes) of package /linux/misc/dns/nsd-4.3.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "axfr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.3.5_vs_4.3.6.

    1 /*
    2  * axfr.c -- generating AXFR responses.
    3  *
    4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
    5  *
    6  * See LICENSE for the license.
    7  *
    8  */
    9 
   10 #include "config.h"
   11 
   12 #include "axfr.h"
   13 #include "dns.h"
   14 #include "packet.h"
   15 #include "options.h"
   16 
   17 /* draft-ietf-dnsop-rfc2845bis-06, section 5.3.1 says to sign every packet */
   18 #define AXFR_TSIG_SIGN_EVERY_NTH    0   /* tsig sign every N packets. */
   19 
   20 query_state_type
   21 query_axfr(struct nsd *nsd, struct query *query)
   22 {
   23     domain_type *closest_match;
   24     domain_type *closest_encloser;
   25     int exact;
   26     int added;
   27     uint16_t total_added = 0;
   28 
   29     if (query->axfr_is_done)
   30         return QUERY_PROCESSED;
   31 
   32     if (query->maxlen > AXFR_MAX_MESSAGE_LEN)
   33         query->maxlen = AXFR_MAX_MESSAGE_LEN;
   34 
   35     assert(!query_overflow(query));
   36     /* only keep running values for most packets */
   37     query->tsig_prepare_it = 0;
   38     query->tsig_update_it = 1;
   39     if(query->tsig_sign_it) {
   40         /* prepare for next updates */
   41         query->tsig_prepare_it = 1;
   42         query->tsig_sign_it = 0;
   43     }
   44 
   45     if (query->axfr_zone == NULL) {
   46         domain_type* qdomain;
   47         /* Start AXFR.  */
   48         STATUP(nsd, raxfr);
   49         exact = namedb_lookup(nsd->db,
   50                       query->qname,
   51                       &closest_match,
   52                       &closest_encloser);
   53 
   54         qdomain = closest_encloser;
   55         query->axfr_zone = domain_find_zone(nsd->db, closest_encloser);
   56 
   57         if (!exact
   58             || query->axfr_zone == NULL
   59             || query->axfr_zone->apex != qdomain
   60             || query->axfr_zone->soa_rrset == NULL)
   61         {
   62             /* No SOA no transfer */
   63             RCODE_SET(query->packet, RCODE_NOTAUTH);
   64             return QUERY_PROCESSED;
   65         }
   66         ZTATUP(nsd, query->axfr_zone, raxfr);
   67 
   68         query->axfr_current_domain = qdomain;
   69         query->axfr_current_rrset = NULL;
   70         query->axfr_current_rr = 0;
   71         if(query->tsig.status == TSIG_OK) {
   72             query->tsig_sign_it = 1; /* sign first packet in stream */
   73         }
   74 
   75         query_add_compression_domain(query, qdomain, QHEADERSZ);
   76 
   77         assert(query->axfr_zone->soa_rrset->rr_count == 1);
   78         added = packet_encode_rr(query,
   79                      query->axfr_zone->apex,
   80                      &query->axfr_zone->soa_rrset->rrs[0],
   81                      query->axfr_zone->soa_rrset->rrs[0].ttl);
   82         if (!added) {
   83             /* XXX: This should never happen... generate error code? */
   84             abort();
   85         }
   86         ++total_added;
   87     } else {
   88         /*
   89          * Query name and EDNS need not be repeated after the
   90          * first response packet.
   91          */
   92         query->edns.status = EDNS_NOT_PRESENT;
   93         buffer_set_limit(query->packet, QHEADERSZ);
   94         QDCOUNT_SET(query->packet, 0);
   95         query_prepare_response(query);
   96     }
   97 
   98     /* Add zone RRs until answer is full.  */
   99     while (query->axfr_current_domain != NULL &&
  100             domain_is_subdomain(query->axfr_current_domain,
  101                         query->axfr_zone->apex))
  102     {
  103         if (!query->axfr_current_rrset) {
  104             query->axfr_current_rrset = domain_find_any_rrset(
  105                 query->axfr_current_domain,
  106                 query->axfr_zone);
  107             query->axfr_current_rr = 0;
  108         }
  109         while (query->axfr_current_rrset) {
  110             if (query->axfr_current_rrset != query->axfr_zone->soa_rrset
  111                 && query->axfr_current_rrset->zone == query->axfr_zone)
  112             {
  113                 while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) {
  114                     added = packet_encode_rr(
  115                         query,
  116                         query->axfr_current_domain,
  117                         &query->axfr_current_rrset->rrs[query->axfr_current_rr],
  118                         query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl);
  119                     if (!added)
  120                         goto return_answer;
  121                     ++total_added;
  122                     ++query->axfr_current_rr;
  123                 }
  124             }
  125 
  126             query->axfr_current_rrset = query->axfr_current_rrset->next;
  127             query->axfr_current_rr = 0;
  128         }
  129         assert(query->axfr_current_domain);
  130         query->axfr_current_domain
  131             = domain_next(query->axfr_current_domain);
  132     }
  133 
  134     /* Add terminating SOA RR.  */
  135     assert(query->axfr_zone->soa_rrset->rr_count == 1);
  136     added = packet_encode_rr(query,
  137                  query->axfr_zone->apex,
  138                  &query->axfr_zone->soa_rrset->rrs[0],
  139                  query->axfr_zone->soa_rrset->rrs[0].ttl);
  140     if (added) {
  141         ++total_added;
  142         query->tsig_sign_it = 1; /* sign last packet */
  143         query->axfr_is_done = 1;
  144     }
  145 
  146 return_answer:
  147     AA_SET(query->packet);
  148     ANCOUNT_SET(query->packet, total_added);
  149     NSCOUNT_SET(query->packet, 0);
  150     ARCOUNT_SET(query->packet, 0);
  151 
  152     /* check if it needs tsig signatures */
  153     if(query->tsig.status == TSIG_OK) {
  154 #if AXFR_TSIG_SIGN_EVERY_NTH > 0
  155         if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) {
  156 #endif
  157             query->tsig_sign_it = 1;
  158 #if AXFR_TSIG_SIGN_EVERY_NTH > 0
  159         }
  160 #endif
  161     }
  162     query_clear_compression_tables(query);
  163     return QUERY_IN_AXFR;
  164 }
  165 
  166 /*
  167  * Answer if this is an AXFR or IXFR query.
  168  */
  169 query_state_type
  170 answer_axfr_ixfr(struct nsd *nsd, struct query *q)
  171 {
  172     struct acl_options *acl = NULL;
  173     /* Is it AXFR? */
  174     switch (q->qtype) {
  175     case TYPE_AXFR:
  176         if (q->tcp) {
  177             struct zone_options* zone_opt;
  178             zone_opt = zone_options_find(nsd->options, q->qname);
  179             if(!zone_opt ||
  180                acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1)
  181             {
  182                 if (verbosity >= 2) {
  183                     char a[128];
  184                     addr2str(&q->addr, a, sizeof(a));
  185                     VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s",
  186                         dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches"));
  187                 }
  188                 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s",
  189                     acl?"blocked":"no acl matches"));
  190                 if (!zone_opt) {
  191                     RCODE_SET(q->packet, RCODE_NOTAUTH);
  192                 } else {
  193                     RCODE_SET(q->packet, RCODE_REFUSE);
  194                     /* RFC8914 - Extended DNS Errors
  195                      * 4.19.  Extended DNS Error Code 18 - Prohibited */
  196                     q->edns.ede = EDE_PROHIBITED;
  197                 }
  198                 return QUERY_PROCESSED;
  199             }
  200             DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s",
  201                 acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
  202             if (verbosity >= 1) {
  203                 char a[128];
  204                 addr2str(&q->addr, a, sizeof(a));
  205                 VERBOSITY(1, (LOG_INFO, "%s for %s from %s",
  206                     (q->qtype==TYPE_AXFR?"axfr":"ixfr"),
  207                     dname_to_string(q->qname, NULL), a));
  208             }
  209             return query_axfr(nsd, q);
  210         }
  211         /* AXFR over UDP queries are discarded. */
  212         RCODE_SET(q->packet, RCODE_IMPL);
  213         return QUERY_PROCESSED;
  214     case TYPE_IXFR:
  215         /* get rid of authority section, if present */
  216         NSCOUNT_SET(q->packet, 0);
  217         if(QDCOUNT(q->packet) > 0 && (size_t)QHEADERSZ+4+
  218             q->qname->name_size <= buffer_limit(q->packet)) {
  219             buffer_set_position(q->packet, QHEADERSZ+4+
  220                 q->qname->name_size);
  221         }
  222         RCODE_SET(q->packet, RCODE_IMPL);
  223         return QUERY_PROCESSED;
  224     default:
  225         return QUERY_DISCARDED;
  226     }
  227 }