Logo Search packages:      
Sourcecode: unbound version File versions  Download package

static int processInitRequest ( struct module_qstate qstate,
struct iter_qstate iq,
struct iter_env ie,
int  id 
) [static]

Process the initial part of the request handling. This state roughly corresponds to resolver algorithms steps 1 (find answer in cache) and 2 (find the best servers to ask).

Note that all requests start here, and query restarts revisit this state.

This state either generates: 1) a response, from cache or error, 2) a priming event, or 3) forwards the request to the next state (init2, generally).

Parameters:
qstate,: query state.
iq,: iterator query state.
ie,: iterator shared global environment.
id,: module id.
Returns:
true if the event needs more request processing immediately, false if not.

Definition at line 652 of file iterator.c.

References iter_qstate::deleg_msg, delegpt_copy(), delegpt_log(), iter_qstate::depth, dname_is_root(), dname_remove_label(), dns_cache_find_delegation(), dns_cache_lookup(), iter_qstate::dp, module_qstate::env, error_response(), final_state(), forward_request(), handle_cname_response(), iter_env::hints, hints_lookup_root(), INIT_REQUEST_2_STATE, INIT_REQUEST_STATE, iter_dp_is_useless(), log_dns_msg(), log_err(), log_query_info(), iter_env::max_dependency_depth, MAX_RESTART_COUNT, delegpt::name, delegpt::namelen, next_state(), module_env::now, prime_root(), iter_qstate::qchase, query_info::qclass, dns_msg::qinfo, module_qstate::qinfo, query_info::qname, query_info::qname_len, query_info::qtype, iter_qstate::query_restart_count, QUERYTARGETS_STATE, iter_qstate::refetch_glue, module_qstate::region, dns_msg::rep, iter_qstate::response, RESPONSE_TYPE_CNAME, response_type_from_cache(), module_env::scratch, VERB_ALGO, VERB_DETAIL, VERB_QUERY, verbose(), and verbosity.

Referenced by iter_handle().

{
      uint8_t* delname;
      size_t delnamelen;
      struct dns_msg* msg;

      log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
      /* check effort */

      /* We enforce a maximum number of query restarts. This is primarily a
       * cheap way to prevent CNAME loops. */
      if(iq->query_restart_count > MAX_RESTART_COUNT) {
            verbose(VERB_QUERY, "request has exceeded the maximum number"
                  " of query restarts with %d", iq->query_restart_count);
            return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
      }

      /* We enforce a maximum recursion/dependency depth -- in general, 
       * this is unnecessary for dependency loops (although it will 
       * catch those), but it provides a sensible limit to the amount 
       * of work required to answer a given query. */
      verbose(VERB_ALGO, "request has dependency depth of %d", iq->depth);
      if(iq->depth > ie->max_dependency_depth) {
            verbose(VERB_QUERY, "request has exceeded the maximum "
                  "dependency depth with depth of %d", iq->depth);
            return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
      }

      /* Resolver Algorithm Step 1 -- Look for the answer in local data. */

      /* This either results in a query restart (CNAME cache response), a
       * terminating response (ANSWER), or a cache miss (null). */
      
      msg = dns_cache_lookup(qstate->env, iq->qchase.qname, 
            iq->qchase.qname_len, iq->qchase.qtype, 
            iq->qchase.qclass, qstate->region, qstate->env->scratch);
      if(msg) {
            /* handle positive cache response */
            enum response_type type = response_type_from_cache(msg, 
                  &iq->qchase);
            if(verbosity >= VERB_ALGO)
                  log_dns_msg("msg from cache lookup", &msg->qinfo, 
                        msg->rep);

            if(type == RESPONSE_TYPE_CNAME) {
                  uint8_t* sname = 0;
                  size_t slen = 0;
                  verbose(VERB_ALGO, "returning CNAME response from "
                        "cache");
                  if(!handle_cname_response(qstate, iq, msg, 
                        &sname, &slen))
                        return error_response(qstate, id, 
                              LDNS_RCODE_SERVFAIL);
                  iq->qchase.qname = sname;
                  iq->qchase.qname_len = slen;
                  /* This *is* a query restart, even if it is a cheap 
                   * one. */
                  iq->query_restart_count++;
                  return next_state(iq, INIT_REQUEST_STATE);
            }

            /* it is an answer, response, to final state */
            verbose(VERB_ALGO, "returning answer from cache.");
            iq->response = msg;
            return final_state(iq);
      }
      
      /* attempt to forward the request */
      if(forward_request(qstate, iq, ie))
      {
            if(!iq->dp) {
                  log_err("alloc failure for forward dp");
                  return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
            }
            /* the request has been forwarded.
             * forwarded requests need to be immediately sent to the 
             * next state, QUERYTARGETS. */
            return next_state(iq, QUERYTARGETS_STATE);
      }

      /* Resolver Algorithm Step 2 -- find the "best" servers. */

      /* first, adjust for DS queries. To avoid the grandparent problem, 
       * we just look for the closest set of server to the parent of qname.
       * When re-fetching glue we also need to ask the parent.
       */
      if(iq->refetch_glue) {
            if(!iq->dp) {
                  log_err("internal or malloc fail: no dp for refetch");
                  return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
            }
            delname = iq->dp->name;
            delnamelen = iq->dp->namelen;
      } else {
            delname = iq->qchase.qname;
            delnamelen = iq->qchase.qname_len;
      }
      if((iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue)
            && !dname_is_root(delname)) {
            /* do not adjust root label, remove first label from delname */
            dname_remove_label(&delname, &delnamelen);
            iq->refetch_glue = 0; /* if CNAME causes restart, no refetch */
      }
      while(1) {
            
            /* Lookup the delegation in the cache. If null, then the 
             * cache needs to be primed for the qclass. */
            iq->dp = dns_cache_find_delegation(qstate->env, delname, 
                  delnamelen, iq->qchase.qtype, iq->qchase.qclass, 
                  qstate->region, &iq->deleg_msg, *qstate->env->now);

            /* If the cache has returned nothing, then we have a 
             * root priming situation. */
            if(iq->dp == NULL) {
                  /* Note that the result of this will set a new
                   * DelegationPoint based on the result of priming. */
                  if(!prime_root(qstate, iq, ie, id, iq->qchase.qclass))
                        return error_response(qstate, id, 
                              LDNS_RCODE_REFUSED);

                  /* priming creates and sends a subordinate query, with 
                   * this query as the parent. So further processing for 
                   * this event will stop until reactivated by the 
                   * results of priming. */
                  return 0;
            }

            /* see if this dp not useless.
             * It is useless if:
             *    o all NS items are required glue. 
             *      or the query is for NS item that is required glue.
             *    o no addresses are provided.
             *    o RD qflag is on.
             * Instead, go up one level, and try to get even further
             * If the root was useless, use safety belt information. 
             * Only check cache returns, because replies for servers
             * could be useless but lead to loops (bumping into the
             * same server reply) if useless-checked.
             */
            if(iter_dp_is_useless(qstate, iq->dp)) {
                  if(dname_is_root(iq->dp->name)) {
                        /* use safety belt */
                        verbose(VERB_QUERY, "Cache has root NS but "
                        "no addresses. Fallback to the safety belt.");
                        iq->dp = hints_lookup_root(ie->hints, 
                              iq->qchase.qclass);
                        /* note deleg_msg is from previous lookup,
                         * but RD is on, so it is not used */
                        if(!iq->dp) {
                              log_err("internal error: no hints dp");
                              return error_response(qstate, id, 
                                    LDNS_RCODE_REFUSED);
                        }
                        iq->dp = delegpt_copy(iq->dp, qstate->region);
                        if(!iq->dp) {
                              log_err("out of memory in safety belt");
                              return error_response(qstate, id, 
                                    LDNS_RCODE_SERVFAIL);
                        }
                        break;
                  } else {
                        verbose(VERB_ALGO, 
                              "cache delegation was useless:");
                        delegpt_log(VERB_ALGO, iq->dp);
                        /* go up */
                        delname = iq->dp->name;
                        delnamelen = iq->dp->namelen;
                        dname_remove_label(&delname, &delnamelen);
                  }
            } else break;
      }

      verbose(VERB_ALGO, "cache delegation returns delegpt");
      delegpt_log(VERB_ALGO, iq->dp);

      /* Otherwise, set the current delegation point and move on to the 
       * next state. */
      return next_state(iq, INIT_REQUEST_2_STATE);
}


Generated by  Doxygen 1.6.0   Back to index