]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- xfr-soa-tls, implement XFR probe for SOA using DNS over TLS.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 19 Oct 2023 14:39:01 +0000 (16:39 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 19 Oct 2023 14:39:01 +0000 (16:39 +0200)
services/authzone.c
services/authzone.h
util/fptr_wlist.c

index 6e6b650cf626bd84fb36e3bbe4f1eea6a5e062a1..17fc320bbc46861b55eb8a7cff22aa42dc88080c 100644 (file)
@@ -6345,7 +6345,10 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
 
        /* get master addr */
        if(xfr->task_probe->scan_addr) {
-               if(!authextstrtoaddr(xfr->task_probe->scan_specific->host, &addr, &addrlen, &auth_name)) {
+               /* parse the host string to get the auth name for scan_addr */
+               if(xfr->task_probe->scan_specific &&
+                       xfr->task_probe->scan_specific->host &&
+                       !authextstrtoaddr(xfr->task_probe->scan_specific->host, &addr, &addrlen, &auth_name)) {
                        char zname[255+1];
                        dname_str(xfr->name, zname);
                        log_err("%s: failed lookup, cannot probe to master %s",
@@ -6365,18 +6368,6 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
                                zname, master->host);
                        return 0;
                }
-               if (auth_name != NULL) {
-                       if (addr.ss_family == AF_INET
-                       &&  (int)ntohs(((struct sockaddr_in *)&addr)->sin_port)
-                           == env->cfg->ssl_port)
-                               ((struct sockaddr_in *)&addr)->sin_port
-                                       = htons((uint16_t)env->cfg->port);
-                       else if (addr.ss_family == AF_INET6
-                       &&  (int)ntohs(((struct sockaddr_in6 *)&addr)->sin6_port)
-                           == env->cfg->ssl_port)
-                               ((struct sockaddr_in6 *)&addr)->sin6_port
-                                       = htons((uint16_t)env->cfg->port);
-               }
        }
 
        /* create packet */
@@ -6386,11 +6377,12 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
                xfr->task_probe->id = GET_RANDOM_ID(env->rnd);
        xfr_create_soa_probe_packet(xfr, env->scratch_buffer, 
                xfr->task_probe->id);
-       /* we need to remove the cp if we have a different ip4/ip6 type now */
+       /* we need to remove the cp if we have a different ip4/ip6 type now.
+        * And also for tls probes to get a new tcp commpoint. */
        if(xfr->task_probe->cp &&
                ((xfr->task_probe->cp_is_ip6 && !addr_is_ip6(&addr, addrlen)) ||
-               (!xfr->task_probe->cp_is_ip6 && addr_is_ip6(&addr, addrlen)))
-               ) {
+               (!xfr->task_probe->cp_is_ip6 && addr_is_ip6(&addr, addrlen)) ||
+               auth_name != NULL)) {
                comm_point_delete(xfr->task_probe->cp);
                xfr->task_probe->cp = NULL;
        }
@@ -6398,14 +6390,19 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
                if(addr_is_ip6(&addr, addrlen))
                        xfr->task_probe->cp_is_ip6 = 1;
                else    xfr->task_probe->cp_is_ip6 = 0;
-               xfr->task_probe->cp = outnet_comm_point_for_udp(env->outnet,
-                       auth_xfer_probe_udp_callback, xfr, &addr, addrlen);
+               if(auth_name != NULL)
+                       xfr->task_probe->cp = outnet_comm_point_for_tcp(env->outnet,
+                               auth_xfer_probe_tcp_callback, xfr, &addr, addrlen, env->scratch_buffer, -1, auth_name != NULL, auth_name);
+               else
+                       xfr->task_probe->cp = outnet_comm_point_for_udp(env->outnet,
+                               auth_xfer_probe_udp_callback, xfr, &addr, addrlen);
                if(!xfr->task_probe->cp) {
                        char zname[255+1], as[256];
                        dname_str(xfr->name, zname);
                        addr_to_str(&addr, addrlen, as, sizeof(as));
-                       verbose(VERB_ALGO, "cannot create udp cp for "
-                               "probe %s to %s", zname, as);
+                       verbose(VERB_ALGO, "cannot create %s cp for "
+                               "probe %s to %s", (auth_name?"tcp":"udp"),
+                               zname, as);
                        return 0;
                }
        }
@@ -6418,16 +6415,9 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
                }
        }
 
-       if(1) {
-               /* DEBUG */
-               char zname[255+1], as[256];
-               dname_str(xfr->name, zname);
-               addr_to_str(&addr, addrlen, as, sizeof(as));
-               verbose(VERB_ALGO, "send soa probe for %s to %s", zname, as);
-               log_addr(VERB_ALGO, "soa probe addr", &addr, addrlen);
-       }
-       /* send udp packet */
-       if(!comm_point_send_udp_msg(xfr->task_probe->cp, env->scratch_buffer,
+       /* send udp packet, for an UDP commpoint. */
+       if(auth_name == NULL &&
+          !comm_point_send_udp_msg(xfr->task_probe->cp, env->scratch_buffer,
                (struct sockaddr*)&addr, addrlen, 0)) {
                char zname[255+1], as[256];
                dname_str(xfr->name, zname);
@@ -6436,13 +6426,18 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
                        zname, as);
                return 0;
        }
+       /* for a TCP commpoint, the packet is waiting to be sent in the
+        * TCP commpoint buffer. The callback returns when there is a reply. */
        if(verbosity >= VERB_ALGO) {
                char zname[255+1], as[256];
                dname_str(xfr->name, zname);
                addr_to_str(&addr, addrlen, as, sizeof(as));
-               verbose(VERB_ALGO, "auth zone %s soa probe sent to %s", zname,
-                       as);
+               verbose(VERB_ALGO, "auth zone %s soa probe sent to %s%s%s",
+                       zname, as, (auth_name?"#":""),
+                       (auth_name?auth_name:""));
        }
+       if(auth_name != NULL)
+               timeout *= 10; /* TCP and TLS get a longer timeout */
        xfr->task_probe->timeout = timeout;
 #ifndef S_SPLINT_S
        t.tv_sec = timeout/1000;
@@ -6580,6 +6575,94 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
        return 0;
 }
 
+/** callback for task_probe tcp replies */
+int
+auth_xfer_probe_tcp_callback(struct comm_point* c, void* arg, int err,
+       struct comm_reply* ATTR_UNUSED(repinfo))
+{
+       struct auth_xfer* xfr = (struct auth_xfer*)arg;
+       struct module_env* env;
+       log_assert(xfr->task_probe);
+       lock_basic_lock(&xfr->lock);
+       env = xfr->task_probe->env;
+       if(!env || env->outnet->want_to_quit) {
+               lock_basic_unlock(&xfr->lock);
+               return 0; /* stop on quit */
+       }
+       /* stop the timer */
+       comm_timer_disable(xfr->task_probe->timer);
+
+       /* see if we got a reply and what that means */
+       if(err == NETEVENT_NOERROR) {
+               uint32_t serial = 0;
+               if(check_packet_ok(c->buffer, LDNS_RR_TYPE_SOA, xfr,
+                       &serial)) {
+                       /* successful lookup */
+                       if(verbosity >= VERB_ALGO) {
+                               char buf[256];
+                               dname_str(xfr->name, buf);
+                               verbose(VERB_ALGO, "auth zone %s: soa probe "
+                                       "serial is %u", buf, (unsigned)serial);
+                       }
+                       /* see if this serial indicates that the zone has
+                        * to be updated */
+                       if(xfr_serial_means_update(xfr, serial)) {
+                               /* if updated, start the transfer task, if needed */
+                               verbose(VERB_ALGO, "auth_zone updated, start transfer");
+                               if(xfr->task_transfer->worker == NULL) {
+                                       struct auth_master* master =
+                                               xfr_probe_current_master(xfr);
+                                       /* if we have download URLs use them
+                                        * in preference to this master we
+                                        * just probed the SOA from */
+                                       if(xfr->task_transfer->masters &&
+                                               xfr->task_transfer->masters->http)
+                                               master = NULL;
+                                       xfr_probe_disown(xfr);
+                                       xfr_start_transfer(xfr, env, master);
+                                       return 0;
+
+                               }
+                               /* other tasks are running, we don't do this anymore */
+                               xfr_probe_disown(xfr);
+                               lock_basic_unlock(&xfr->lock);
+                               /* return, we don't sent a reply to this udp packet,
+                                * and we setup the tasks to do next */
+                               return 0;
+                       } else {
+                               verbose(VERB_ALGO, "auth_zone master reports unchanged soa serial");
+                               /* we if cannot find updates amongst the
+                                * masters, this means we then have a new lease
+                                * on the zone */
+                               xfr->task_probe->have_new_lease = 1;
+                       }
+               } else {
+                       if(verbosity >= VERB_ALGO) {
+                               char buf[256];
+                               dname_str(xfr->name, buf);
+                               verbose(VERB_ALGO, "auth zone %s: bad reply to soa probe", buf);
+                       }
+               }
+       } else {
+               if(verbosity >= VERB_ALGO) {
+                       char buf[256];
+                       dname_str(xfr->name, buf);
+                       verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf);
+               }
+       }
+
+       /* failed lookup or not an update */
+       /* delete commpoint so a new one is created, with a fresh port nr */
+       comm_point_delete(xfr->task_probe->cp);
+       xfr->task_probe->cp = NULL;
+
+       /* if the result was not a successful probe, we need
+        * to send the next one */
+       xfr_probe_nextmaster(xfr);
+       xfr_probe_send_or_end(xfr, env);
+       return 0;
+}
+
 /** lookup a host name for its addresses, if needed */
 static int
 xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
index 07614ed82963d33b37891b20a781db318be2843a..6d220443b945837ad80cf741a9540fbb8244d612 100644 (file)
@@ -678,6 +678,9 @@ void auth_xfer_timer(void* arg);
 /** callback for commpoint udp replies to task_probe */
 int auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err,
         struct comm_reply* repinfo);
+/** callback for commpoint tcp replies to task_probe */
+int auth_xfer_probe_tcp_callback(struct comm_point* c, void* arg, int err,
+        struct comm_reply* repinfo);
 /** callback for task_transfer tcp connections */
 int auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
         struct comm_reply* repinfo);
index 43d38dc3797ddd7316ea90bebc35a7aa9ba70ee1..c719580f7e33ac188a250db5d36e3d683bd75464 100644 (file)
@@ -108,6 +108,7 @@ fptr_whitelist_comm_point(comm_point_callback_type *fptr)
        else if(fptr == &outnet_tcp_cb) return 1;
        else if(fptr == &tube_handle_listen) return 1;
        else if(fptr == &auth_xfer_probe_udp_callback) return 1;
+       else if(fptr == &auth_xfer_probe_tcp_callback) return 1;
        else if(fptr == &auth_xfer_transfer_tcp_callback) return 1;
        else if(fptr == &auth_xfer_transfer_http_callback) return 1;
        return 0;