]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Start with SVCB AliasMode processing ietf120-hackathon/svcb-alias-processing 1109/head
authorWillem Toorop <willem@nlnetlabs.nl>
Sun, 21 Jul 2024 17:11:11 +0000 (10:11 -0700)
committerWillem Toorop <willem@nlnetlabs.nl>
Sun, 21 Jul 2024 17:11:11 +0000 (10:11 -0700)
As requested by @nialor in issue #1065.
This may be of benefit (when completed) to DELEG as well.

iterator/iterator.c

index cddb02717a0a59a2906b413e190cb4a90af2a572..6202144c3203330336b08c37ac3bdd5acc0e38b3 100644 (file)
@@ -575,6 +575,63 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
        return 1;
 }
 
+static int
+get_svcb_alias_target(struct ub_packed_rrset_key* r,
+       uint8_t** mname, size_t* mname_len)
+{
+       size_t i;
+       struct packed_rrset_data* d = (struct packed_rrset_data*)r->entry.data;
+       (void)r; (void)mname; (void)mname_len;
+
+       for(i=0; i<d->count; i++) {
+               size_t t_len; /* TargetName length */
+
+               if(d->rr_len[i] <= 5
+               || ((uint16_t*)d->rr_data[i])[1] != 0
+               || !(t_len = dname_valid(d->rr_data[i] + 4, d->rr_len[i] - 4)))
+                       continue;
+               *mname = d->rr_data[i] + 4;
+               *mname_len = t_len;
+               return 1;
+       }
+       return 0;
+}
+
+static int
+handle_svcb_alias(struct module_qstate* qstate, struct iter_qstate* iq,
+        struct dns_msg* msg, uint8_t** mname, size_t* mname_len)
+{
+       int new_target = 0;
+       size_t i;
+       (void)qstate;(void)iq;(void)msg;(void)mname;(void)mname_len;
+
+       assert(iq->qchase.qtype == LDNS_RR_TYPE_SVCB
+           || iq->qchase.qtype == LDNS_RR_TYPE_HTTPS);
+       /* Start with the (current) qname. */
+       *mname = iq->qchase.qname;
+       *mname_len = iq->qchase.qname_len;
+
+       /* Iterate over the ANSWER rrsets in order, looking for SVCB or HTTPS
+        *
+        */
+       for(i=0; i<msg->rep->an_numrrsets; i++) {
+               struct ub_packed_rrset_key* r = msg->rep->rrsets[i];
+
+               if(ntohs(r->rk.type) == iq->qchase.qtype
+               && query_dname_compare(*mname, r->rk.dname) == 0
+               && get_svcb_alias_target(r, mname, mname_len)
+               && !iter_find_rrset_in_prepend_answer(iq, r)) {
+                       /* Add this relevant SVCB rrset to the prepend list.*/
+                       if(!iter_add_prepend_answer(qstate, iq, r))
+                               return 0;
+                       else
+                               new_target = 1;
+               }
+               /* Other rrsets in the section are ignored. */
+       }
+       return new_target;
+}
+
 /** fill fail address for later recovery */
 static void
 fill_fail_addr(struct iter_qstate* iq, struct sockaddr_storage* addr,
@@ -3226,6 +3283,9 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
 
        /* handle each of the type cases */
        if(type == RESPONSE_TYPE_ANSWER) {
+               uint8_t* sname = NULL;
+               size_t snamelen = 0;
+
                /* ANSWER type responses terminate the query algorithm, 
                 * so they sent on their */
                if(verbosity >= VERB_DETAIL) {
@@ -3258,6 +3318,45 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                                iq->dp&&iq->dp->has_parent_side_NS,
                                qstate->region, qstate->query_flags,
                                qstate->qstarttime);
+               if((  iq->qchase.qtype == LDNS_RR_TYPE_SVCB
+                  || iq->qchase.qtype == LDNS_RR_TYPE_HTTPS)
+               && handle_svcb_alias(qstate, iq, iq->response, &sname, &snamelen)) {
+
+                       /* set the current request's qname to the new value. */
+                       iq->qchase.qname = sname;
+                       iq->qchase.qname_len = snamelen;
+                       /* Clear the query state, since this is a query restart. */
+                       iq->deleg_msg = NULL;
+                       iq->dp = NULL;
+                       iq->dsns_point = NULL;
+                       iq->auth_zone_response = 0;
+                       iq->sent_count = 0;
+                       iq->dp_target_count = 0;
+                       if(iq->minimisation_state != MINIMISE_STATE)
+                               /* Only count as query restart when it is not an extra
+                                * query as result of qname minimisation. */
+                               iq->query_restart_count++;
+                       if(qstate->env->cfg->qname_minimisation)
+                               iq->minimisation_state = INIT_MINIMISE_STATE;
+
+                       /* stop current outstanding queries.
+                        * FIXME: should the outstanding queries be waited for and
+                        * handled? Say by a subquery that inherits the outbound_entry.
+                        */
+                       outbound_list_clear(&iq->outlist);
+                       iq->num_current_queries = 0;
+                       fptr_ok(fptr_whitelist_modenv_detach_subs(
+                               qstate->env->detach_subs));
+                       (*qstate->env->detach_subs)(qstate);
+                       iq->num_target_queries = 0;
+                       if(qstate->reply)
+                               sock_list_insert(&qstate->reply_origin,
+                                       &qstate->reply->remote_addr,
+                                       qstate->reply->remote_addrlen, qstate->region);
+                       verbose(VERB_ALGO, "cleared outbound list for query restart");
+                       /* go to INIT_REQUEST_STATE for new qname. */
+                       return next_state(iq, INIT_REQUEST_STATE);
+               }
                /* close down outstanding requests to be discarded */
                outbound_list_clear(&iq->outlist);
                iq->num_current_queries = 0;