- xfr-soa-tls, implement XFR probe for SOA using DNS over TLS.

This commit is contained in:
W.C.A. Wijngaards 2023-10-19 16:39:01 +02:00
parent f830ee89e3
commit dfaf5ce5dc
3 changed files with 119 additions and 32 deletions

View 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)

View 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);

View 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;