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

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

This is the request event state where the request will be sent to one of its current query targets. This state also handles issuing target lookup queries for missing target IP addresses. Queries typically iterate on this state, both when they are just trying different targets for a given delegation point, and when they change delegation points. This state roughly corresponds to RFC 1034 algorithm steps 3 and 4.

qstate,: query state.
iq,: iterator query state.
ie,: iterator shared global environment.
id,: module id.
true if the event requires more request processing immediately, false if not. This state only returns true when it is generating a SERVFAIL response because the query has hit a dead end.

Definition at line 1038 of file iterator.c.

References delegpt_addr::addr, delegpt_addr::addrlen, BIT_CD, iter_qstate::chase_flags, delegpt_add_unused_targets(), delegpt_count_missing_targets(), delegpt_log(), iter_qstate::depth, iter_qstate::dnssec_expected, iter_qstate::dp, EDNS_DO, module_qstate::env, error_response(), module_qstate::ext_state, fptr_ok, fptr_whitelist_modenv_send_query(), iter_server_selection(), log_addr(), log_name_addr(), log_query_info(), iter_env::max_dependency_depth, MAX_REFERRAL_COUNT, module_wait_reply, delegpt::name, delegpt::namelen, next_state(), iter_qstate::num_current_queries, iter_qstate::num_target_queries, outbound_list_insert(), iter_qstate::outlist, iter_qstate::qchase, query_info::qclass, module_qstate::qinfo, query_info::qname, query_info::qname_len, query_info::qtype, query_for_targets(), QUERYTARGETS_STATE, iter_qstate::referral_count, module_env::send_query, iter_env::target_fetch_policy, VERB_ALGO, VERB_OPS, VERB_QUERY, and verbose().

Referenced by iter_handle().

      int tf_policy;
      struct delegpt_addr* target;
      struct outbound_entry* outq;

      /* NOTE: a request will encounter this state for each target it 
       * needs to send a query to. That is, at least one per referral, 
       * more if some targets timeout or return throwaway answers. */

      log_query_info(VERB_QUERY, "processQueryTargets:", &qstate->qinfo);
      verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
            "currentqueries %d", iq->num_target_queries, 
      qstate->ext_state[id] = module_wait_reply;

      /* Make sure that we haven't run away */
      /* FIXME: is this check even necessary? */
      if(iq->referral_count > MAX_REFERRAL_COUNT) {
            verbose(VERB_QUERY, "request has exceeded the maximum "
                  "number of referrrals with %d", iq->referral_count);
            return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
      /* Make sure we have a delegation point, otherwise priming failed
       * or another failure occurred */
      if(!iq->dp) {
            verbose(VERB_QUERY, "Failed to get a delegation, giving up");
            return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
      delegpt_log(VERB_ALGO, iq->dp);

      if(iq->num_current_queries>0) {
            /* already busy answering a query, this restart is because
             * more delegpt addrs became available, wait for existing
             * query. */
            verbose(VERB_ALGO, "woke up, but wait for outstanding query");
            return 0;

      tf_policy = 0;
      if(iq->depth <= ie->max_dependency_depth) {
            tf_policy = ie->target_fetch_policy[iq->depth];

      /* if there is a policy to fetch missing targets 
       * opportunistically, do it. we rely on the fact that once a 
       * query (or queries) for a missing name have been issued, 
       * they will not be show up again. */
      if(tf_policy != 0) {
            int extra = 0;
            verbose(VERB_ALGO, "attempt to get extra %d targets", 
            if(!query_for_targets(qstate, iq, ie, id, tf_policy, &extra)) {
                  return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
            iq->num_target_queries += extra;

      /* Add the current set of unused targets to our queue. */

      /* Select the next usable target, filtering out unsuitable targets. */
      target = iter_server_selection(ie, qstate->env, iq->dp, 
            iq->dp->name, iq->dp->namelen, &iq->dnssec_expected);

      /* If no usable target was selected... */
      if(!target) {
            /* Here we distinguish between three states: generate a new 
             * target query, just wait, or quit (with a SERVFAIL).
             * We have the following information: number of active 
             * target queries, number of active current queries, 
             * the presence of missing targets at this delegation 
             * point, and the given query target policy. */
            /* Check for the wait condition. If this is true, then 
             * an action must be taken. */
            if(iq->num_target_queries==0 && iq->num_current_queries==0) {
                  /* If there is nothing to wait for, then we need 
                   * to distinguish between generating (a) new target 
                   * query, or failing. */
                  if(delegpt_count_missing_targets(iq->dp) > 0) {
                        int qs = 0;
                        verbose(VERB_ALGO, "querying for next "
                              "missing target");
                        if(!query_for_targets(qstate, iq, ie, id, 
                              1, &qs)) {
                              return error_response(qstate, id,
                        iq->num_target_queries += qs;
                  /* Since a target query might have been made, we 
                   * need to check again. */
                  if(iq->num_target_queries == 0) {
                        verbose(VERB_QUERY, "out of query targets -- "
                              "returning SERVFAIL");
                        /* fail -- no more targets, no more hope 
                         * of targets, no hope of a response. */
                        return error_response(qstate, id,

            /* otherwise, we have no current targets, so submerge 
             * until one of the target or direct queries return. */
            if(iq->num_target_queries>0 && iq->num_current_queries>0)
                  verbose(VERB_ALGO, "no current targets -- waiting "
                        "for %d targets to resolve or %d outstanding"
                        " queries to respond", iq->num_target_queries, 
            else if(iq->num_target_queries>0)
                  verbose(VERB_ALGO, "no current targets -- waiting "
                        "for %d targets to resolve.",
            else  verbose(VERB_ALGO, "no current targets -- waiting "
                        "for %d outstanding queries to respond.",
            return 0;

      /* We have a valid target. */
      log_query_info(VERB_QUERY, "sending query:", &iq->qchase);
      log_name_addr(VERB_QUERY, "sending to target:", iq->dp->name, 
            &target->addr, target->addrlen);
      outq = (*qstate->env->send_query)(
            iq->qchase.qname, iq->qchase.qname_len, 
            iq->qchase.qtype, iq->qchase.qclass, 
            iq->chase_flags, EDNS_DO|BIT_CD, 
            &target->addr, target->addrlen, qstate);
      if(!outq) {
            verbose(VERB_OPS, "error sending query to auth server; "
                  "skip this address");
            log_addr(VERB_OPS, "error for address:", 
                  &target->addr, target->addrlen);
            return next_state(iq, QUERYTARGETS_STATE);
      outbound_list_insert(&iq->outlist, outq);
      qstate->ext_state[id] = module_wait_reply;

      return 0;

Generated by  Doxygen 1.6.0   Back to index