From 41e4e4b219589d7ba07079198e7cc747236b2522 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Sat, 25 May 2024 13:48:24 +0200 Subject: [PATCH 1/4] Ask for EDNS expire option on transfers and set the time acquired seconds earlier, so it will expire that value more earlier. --- edns.h | 1 + xfrd-tcp.c | 21 +++++++++ xfrd-tcp.h | 2 + xfrd.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++---- xfrd.h | 2 + 5 files changed, 141 insertions(+), 8 deletions(-) diff --git a/edns.h b/edns.h index 45d7c6361..c257579a6 100644 --- a/edns.h +++ b/edns.h @@ -18,6 +18,7 @@ struct query; #define OPT_RDATA 2 /* holds the rdata length comes after OPT_LEN */ #define OPT_HDR 4U /* NSID opt header length */ #define NSID_CODE 3 /* nsid option code */ +#define EXPIRE_CODE 9 /* RFC 7314 */ #define COOKIE_CODE 10 /* COOKIE option code */ #define EDE_CODE 15 /* Extended DNS Errors option code */ #define DNSSEC_OK_MASK 0x8000U /* do bit mask */ diff --git a/xfrd-tcp.c b/xfrd-tcp.c index daf25e66a..f90ca8e2f 100644 --- a/xfrd-tcp.c +++ b/xfrd-tcp.c @@ -470,6 +470,25 @@ xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_in *frm) #endif /* INET6 */ } +void +xfrd_write_request_edns_expire_option(struct buffer* packet, uint16_t sz) +{ + /* TODO: Track whether a transfer failed with this option (for an + * upstream), and then retry without the option. + */ + /* . OPT */ + ARCOUNT_SET(packet, 1); + buffer_write_u8(packet, 0); + buffer_write_u16(packet, TYPE_OPT); + buffer_write_u16(packet, sz); + buffer_write_u8(packet, 0); /* rcode */ + buffer_write_u8(packet, 0); /* version */ + buffer_write_u16(packet, 0x8000); /* DO flag */ + buffer_write_u16(packet, 2 * sizeof(uint16_t)); /* rdlength */ + buffer_write_u16(packet, EXPIRE_CODE); /* option code */ + buffer_write_u16(packet, 0); /* option length */ +} + void xfrd_write_soa_buffer(struct buffer* packet, const dname_type* apex, struct xfrd_soa* soa, int apex_compress) @@ -1007,6 +1026,7 @@ xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) xfrd_setup_packet(tcp->packet, TYPE_AXFR, CLASS_IN, zone->apex, zone->query_id, NULL); xfrd_prepare_zone_xfr(zone, TYPE_AXFR); + xfrd_write_request_edns_expire_option(tcp->packet, 65535); } else { int apex_compress = 0; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request incremental zone " @@ -1019,6 +1039,7 @@ xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) NSCOUNT_SET(tcp->packet, 1); xfrd_write_soa_buffer(tcp->packet, zone->apex, &zone->soa_disk, apex_compress); + xfrd_write_request_edns_expire_option(tcp->packet, 65535); } if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request( diff --git a/xfrd-tcp.h b/xfrd-tcp.h index 6b3217d2d..4fd364073 100644 --- a/xfrd-tcp.h +++ b/xfrd-tcp.h @@ -229,6 +229,8 @@ void xfrd_setup_packet(struct buffer* packet, /* write soa in network format to the packet buffer */ void xfrd_write_soa_buffer(struct buffer* packet, const struct dname* apex, struct xfrd_soa* soa, int apex_compress); +/* write . OPT RR with empty EXPIRE option */ +void xfrd_write_request_edns_expire_option(struct buffer* packet, uint16_t sz); /* use acl address to setup sockaddr struct, returns length of addr. */ socklen_t xfrd_acl_sockaddr_to(struct acl_options* acl, #ifdef INET6 diff --git a/xfrd.c b/xfrd.c index fbbe4774e..bccdd1cd2 100644 --- a/xfrd.c +++ b/xfrd.c @@ -1900,6 +1900,9 @@ xfrd_send_ixfr_request_udp(xfrd_zone_type* zone) NSCOUNT_SET(xfrd->packet, 1); xfrd_write_soa_buffer(xfrd->packet, zone->apex, &zone->soa_disk, apex_compress); + xfrd_write_request_edns_expire_option(xfrd->packet, + zone->master->is_ipv6 ? xfrd->nsd->options->ipv6_edns_size + : xfrd->nsd->options->ipv4_edns_size); /* if we have tsig keys, sign the ixfr query */ if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request( @@ -2117,6 +2120,76 @@ xfrd_xfr_process_tsig(xfrd_zone_type* zone, buffer_type* packet) return 1; } +static void +xfrd_process_expire_option(buffer_type* packet, xfrd_zone_type* zone) +{ + size_t mempos = buffer_position(packet); + uint16_t rdlen; + + if(!zone->latest_xfr) + return; + + /* len(dname) + len(type) + len(class) + len(ttl) + len(rdlen) = + * 1 + 2 + 2 + 4 + 2 = 11 + * + * len(option_code) + len(option_len) + len(expire_option) = + * 2 + 2 + 4 = 8 + */ + if(!buffer_available(packet, 19) + || buffer_read_u8(packet) != 0 + || buffer_read_u16(packet) != TYPE_OPT) { + buffer_set_position(packet, mempos); + return; + } + /* skip UDP payload, rcode, version, flags (or class and ttl) */ + buffer_skip(packet, 6); + rdlen = buffer_read_u16(packet); + while(rdlen >= 8) { + uint16_t option_code, option_len; + + if(!buffer_available(packet, 8)) + break; + option_code = buffer_read_u16(packet); + option_len = buffer_read_u16(packet); + rdlen -= 4; + if(option_code == EXPIRE_CODE && option_len == 4) { + zone->latest_xfr->msg_has_expire_option = 1; + zone->latest_xfr->msg_expire_option_value = + buffer_read_u32(packet); + log_msg(LOG_INFO, "expire option set to %d for zone %s" + , (int)zone->latest_xfr->msg_expire_option_value + , zone->apex_str); + break; + } + /* skip option */ + if (option_len > rdlen + || !buffer_available(packet, option_len)) + break; + buffer_skip(packet, option_len); + rdlen -= option_len; + } + buffer_set_position(packet, mempos); +} + + +static time_t +xfrd_time_adjusted_for_expire_option_value(xfrd_zone_type* zone) +{ + uint32_t soa_expire = ntohl(zone->soa_disk.expire); + + log_msg(LOG_INFO, "(%d) time adjusted with %d for zone %s" + , (int)zone->latest_xfr->msg_has_expire_option + , (int)zone->latest_xfr->msg_expire_option_value + , zone->apex_str); + + if(!zone->latest_xfr->msg_has_expire_option + || soa_expire <= zone->latest_xfr->msg_expire_option_value) + return xfrd_time(); + /* Pretend we got it earlier with the to be adjusted amount */ + return xfrd_time() - + (soa_expire - zone->latest_xfr->msg_expire_option_value); +} + /* parse the received packet. returns xfrd packet result code. */ static enum xfrd_packet_result xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, @@ -2126,6 +2199,7 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, size_t qdcount = QDCOUNT(packet); size_t ancount = ANCOUNT(packet), ancount_todo; size_t nscount = NSCOUNT(packet); + size_t arcount = ARCOUNT(packet); int done = 0; region_type* tempregion = NULL; assert(zone->master); @@ -2263,13 +2337,24 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, "update indicating " "current serial", zone->apex_str)); + if(arcount > 0) { + int i; + for(i = ancount - 1 + nscount; i > 0; i--) { + if(!packet_skip_rr(packet, 0)) + break; + } + if(i == 0) { + xfrd_process_expire_option(packet, zone); + } + } /* (even if notified) the lease on the current soa is renewed */ - zone->soa_disk_acquired = xfrd_time(); + zone->soa_disk_acquired = + xfrd_time_adjusted_for_expire_option_value(zone); if(zone->soa_nsd.serial == soa->serial) - zone->soa_nsd_acquired = xfrd_time(); - xfrd_set_zone_state(zone, xfrd_zone_ok); - DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", + zone->soa_nsd_acquired = zone->soa_disk_acquired; + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", zone->apex_str)); + xfrd_set_zone_state(zone, xfrd_zone_ok); if(zone->zone_options->pattern->multi_primary_check) { region_destroy(tempregion); return xfrd_packet_drop; @@ -2332,6 +2417,16 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, region_destroy(tempregion); return xfrd_packet_bad; } + if(arcount > 0) { + int i; + for(i = nscount; i > 0; i--) { + if(!packet_skip_rr(packet, 0)) + break; + } + if(i == 0) { + xfrd_process_expire_option(packet, zone); + } + } region_destroy(tempregion); if(zone->tcp_conn == -1 && done == 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply incomplete")); @@ -2490,9 +2585,20 @@ xfrd_handle_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet) /* done. we are completely sure of this */ buffer_clear(packet); - buffer_printf(packet, "received update to serial %u at %s from %s", - (unsigned)zone->latest_xfr->msg_new_serial, xfrd_pretty_time(xfrd_time()), - zone->master->ip_address_spec); + if(zone->latest_xfr->msg_has_expire_option) + buffer_printf( packet + , "received update to serial %u at %s from %s, " + "set to expire in %u seconds" + , (unsigned)zone->latest_xfr->msg_new_serial + , xfrd_pretty_time(xfrd_time()) + , zone->master->ip_address_spec + , zone->latest_xfr->msg_expire_option_value); + else + buffer_printf( packet + , "received update to serial %u at %s from %s" + , (unsigned)zone->latest_xfr->msg_new_serial + , xfrd_pretty_time(xfrd_time()) + , zone->master->ip_address_spec); if(zone->master->key_options) { buffer_printf(packet, " TSIG verified with key %s", zone->master->key_options->name); @@ -2518,8 +2624,9 @@ xfrd_handle_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet) /* reset msg seq nr, so if that is nonnull we know xfr file exists */ zone->latest_xfr->msg_seq_nr = 0; /* update the disk serial no. */ - zone->soa_disk_acquired = zone->latest_xfr->acquired = xfrd_time(); zone->soa_disk = soa; + zone->soa_disk_acquired = zone->latest_xfr->acquired = + xfrd_time_adjusted_for_expire_option_value(zone); if(zone->soa_notified_acquired && ( zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), diff --git a/xfrd.h b/xfrd.h index 72f3a0565..fcd5a436b 100644 --- a/xfrd.h +++ b/xfrd.h @@ -240,6 +240,8 @@ struct xfrd_xfr { uint32_t msg_old_serial, msg_new_serial; /* host byte order */ size_t msg_rr_count; uint8_t msg_is_ixfr; /* 1:IXFR detected. 2:middle IXFR SOA seen. */ + uint8_t msg_has_expire_option; + uint32_t msg_expire_option_value; tsig_record_type tsig; /* tsig state for IXFR/AXFR */ uint64_t xfrfilenumber; /* identifier for file to store xfr into, valid if msg_seq_nr nonzero */ From 531d100ca7d88d107598d05b25f07fe3bba1466f Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Sat, 25 May 2024 17:13:45 +0200 Subject: [PATCH 2/4] Return EXPIRE option on query --- edns.c | 9 +++++++++ edns.h | 2 ++ query.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/edns.c b/edns.c index 0e1caca29..363f1eece 100644 --- a/edns.c +++ b/edns.c @@ -75,6 +75,8 @@ edns_init_record(edns_record_type *edns) edns->ede = -1; /* -1 means no Extended DNS Error */ edns->ede_text = NULL; edns->ede_text_len = 0; + edns->expire_option_seen = 0; + edns->expire_option_value = 0; } /** handle a single edns option in the query */ @@ -98,6 +100,13 @@ edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, buffer_skip(packet, optlen); } break; + case EXPIRE_CODE: + edns->expire_option_seen = 1; + /* we have to check optlen, and move the buffer along */ + buffer_skip(packet, optlen); + /* in the reply we need space for optcode+optlen+time*/ + edns->opt_reserved_space += OPT_HDR + sizeof(uint32_t); + break; case COOKIE_CODE: /* Cookies enabled? */ if(nsd->do_answer_cookie) { diff --git a/edns.h b/edns.h index c257579a6..a409133d6 100644 --- a/edns.h +++ b/edns.h @@ -66,6 +66,8 @@ struct edns_record int ede; /* RFC 8914 - Extended DNS Errors */ char* ede_text; /* RFC 8914 - Extended DNS Errors text*/ uint16_t ede_text_len; + char expire_option_seen; + uint32_t expire_option_value; }; typedef struct edns_record edns_record_type; diff --git a/query.c b/query.c index 9fbc7a7c4..483e460f3 100644 --- a/query.c +++ b/query.c @@ -1786,6 +1786,8 @@ query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) /* fill with NULLs */ buffer_write(q->packet, edns->rdata_none, OPT_RDATA); } else { + zone_type* expire_zone = NULL; + /* rdata length */ buffer_write_u16(q->packet, q->edns.opt_reserved_space); /* edns options */ @@ -1802,6 +1804,49 @@ query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) cookie_create(q, nsd, now_p); buffer_write(q->packet, q->edns.cookie, 24); } + if(q->edns.expire_option_seen) { + if(q->qtype == TYPE_AXFR) + expire_zone = q->axfr_zone; + else + expire_zone = q->zone; + } + /* Append EXPIRE (RFC 7314) option if needed */ + if(q->edns.expire_option_seen && expire_zone + && expire_zone->soa_rrset && expire_zone->soa_rrset->rrs + && expire_zone->soa_rrset->rrs->type == TYPE_SOA + && expire_zone->soa_rrset->rrs->rdata_count == 7) { + uint32_t expire_value; + + /* OPTION-CODE */ + buffer_write_u16(q->packet, EXPIRE_CODE); + /* OPTION-LENGTH */ + buffer_write_u16(q->packet, sizeof(uint32_t)); + memcpy(&expire_value, rdata_atom_data( + expire_zone->soa_rrset->rrs->rdatas[5]) + , sizeof(uint32_t)); + expire_value = ntohl(expire_value); + if(zone_is_slave(expire_zone->opts)) { + uint32_t now = *now_p ? *now_p + : (*now_p = (uint32_t)time(NULL)); + + if(expire_zone->mtime.tv_sec < now) { + uint32_t passed = now - expire_zone->mtime.tv_sec; + if(passed < expire_value) + expire_value -= passed; + else + expire_value = 0; + } + } + buffer_write_u32(q->packet, expire_value); + } else if(q->edns.expire_option_seen) { + /* OPTION-CODE */ + buffer_write_u16(q->packet, EXPIRE_CODE); + /* OPTION-LENGTH */ + buffer_write_u16(q->packet, sizeof(uint32_t)); + /* OPTION-VALE */ + buffer_write_u32(q->packet, 0); + } + /* Append Extended DNS Error (RFC8914) option if needed */ if (q->edns.ede >= 0) { /* < 0 means no EDE */ /* OPTION-CODE */ From fb78269d2e5115f5822e980aac85a476a2828ca4 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Sat, 25 May 2024 18:23:28 +0200 Subject: [PATCH 3/4] Process EXPIRE option when applying transfers --- difffile.c | 35 ++++++++++++++++++++++++++--- edns.c | 44 +++++++++++++++++++++++++++++++++++++ edns.h | 5 +++++ xfrd.c | 64 +++++++----------------------------------------------- 4 files changed, 89 insertions(+), 59 deletions(-) diff --git a/difffile.c b/difffile.c index c4d18ad96..eb4b26b2a 100644 --- a/difffile.c +++ b/difffile.c @@ -995,10 +995,11 @@ apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, struct zone* zone, int* bytes, - int* softfail, struct ixfr_store* ixfr_store) + int* softfail, struct ixfr_store* ixfr_store, + char* expire_option_seen, uint32_t* expire_option_value) { uint32_t msglen, checklen, pkttype; - int qcount, ancount; + int qcount, ancount, nscount, arcount; buffer_type* packet; region_type* region; @@ -1054,6 +1055,8 @@ apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno, authority section RRs are skipped */ qcount = QDCOUNT(packet); ancount = ANCOUNT(packet); + nscount = NSCOUNT(packet); + arcount = ARCOUNT(packet); buffer_skip(packet, QHEADERSZ); /* qcount should be 0 or 1 really, ancount limited by 64k packet */ if(qcount > 64 || ancount > 65530) { @@ -1245,6 +1248,15 @@ apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno, } } } + if(arcount > 0) { + for(; nscount > 0; nscount--) { + if(!packet_skip_rr(packet, 0)) + break; + } + if(nscount == 0) + *expire_option_seen = process_expire_option( + packet, expire_option_value); + } region_destroy(region); return 1; } @@ -1356,6 +1368,8 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, { int is_axfr=0, delete_mode=0, rr_count=0, softfail=0; struct ixfr_store* ixfr_store = NULL, ixfr_store_mem; + char expire_option_seen = 0; + uint32_t expire_option_value = 0; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf)); if(zone_is_ixfr_enabled(zone)) @@ -1367,7 +1381,8 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, ret = apply_ixfr(nsd, in, new_serial, i, num_parts, &is_axfr, &delete_mode, &rr_count, zone, - &num_bytes, &softfail, ixfr_store); + &num_bytes, &softfail, ixfr_store, + &expire_option_seen, &expire_option_value); if(ret == 0) { log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf); diff_update_commit( @@ -1392,6 +1407,20 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, zone->is_checked = (committed == DIFF_VERIFIED); zone->mtime.tv_sec = time_end_0; zone->mtime.tv_nsec = time_end_1*1000; + if(expire_option_seen && zone->soa_rrset && zone->soa_rrset->rrs + && zone->soa_rrset->rrs->type == TYPE_SOA + && zone->soa_rrset->rrs->rdata_count == 7) { + uint32_t expire_value; + + memcpy(&expire_value, rdata_atom_data( + zone->soa_rrset->rrs->rdatas[5]) + , sizeof(uint32_t)); + expire_value = ntohl(expire_value); + if(expire_option_value < expire_value) { + zone->mtime.tv_sec -= + (expire_value - expire_option_value); + } + } if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); diff --git a/edns.c b/edns.c index 363f1eece..fe7ff4920 100644 --- a/edns.c +++ b/edns.c @@ -348,3 +348,47 @@ void cookie_create(query_type *q, struct nsd* nsd, uint32_t *now_p) memcpy(q->edns.cookie + 16, hash, 8); } +int +process_expire_option(buffer_type* packet, uint32_t* expire_option_value) +{ + size_t mempos = buffer_position(packet); + uint16_t rdlen; + + /* len(dname) + len(type) + len(class) + len(ttl) + len(rdlen) = + * 1 + 2 + 2 + 4 + 2 = 11 + * + * len(option_code) + len(option_len) + len(expire_option) = + * 2 + 2 + 4 = 8 + */ + if(!buffer_available(packet, 19) + || buffer_read_u8(packet) != 0 + || buffer_read_u16(packet) != TYPE_OPT) { + buffer_set_position(packet, mempos); + return 0; + } + /* skip UDP payload, rcode, version, flags (or class and ttl) */ + buffer_skip(packet, 6); + rdlen = buffer_read_u16(packet); + while(rdlen >= 8) { + uint16_t option_code, option_len; + + if(!buffer_available(packet, 8)) + break; + option_code = buffer_read_u16(packet); + option_len = buffer_read_u16(packet); + rdlen -= 4; + if(option_code == EXPIRE_CODE && option_len == 4) { + *expire_option_value = buffer_read_u32(packet); + return 1; + } + /* skip option */ + if (option_len > rdlen + || !buffer_available(packet, option_len)) + break; + buffer_skip(packet, option_len); + rdlen -= option_len; + } + buffer_set_position(packet, mempos); + return 0; +} + diff --git a/edns.h b/edns.h index a409133d6..100c51459 100644 --- a/edns.h +++ b/edns.h @@ -106,4 +106,9 @@ void edns_init_nsid(edns_data_type *data, uint16_t nsid_len); void cookie_verify(struct query *q, struct nsd* nsd, uint32_t *now_p); void cookie_create(struct query *q, struct nsd* nsd, uint32_t *now_p); +/* packet position must point to the additional section (and the OPT RR) + * Returns 1 when the OPT RR contains an EXPIRE option, 0 otherwise. + * When an EXPIRE option is seen, expire_option_value is filled with the value + */ +int process_expire_option(buffer_type* packet, uint32_t* expire_option_value); #endif /* EDNS_H */ diff --git a/xfrd.c b/xfrd.c index bccdd1cd2..bc7ca48af 100644 --- a/xfrd.c +++ b/xfrd.c @@ -2120,58 +2120,6 @@ xfrd_xfr_process_tsig(xfrd_zone_type* zone, buffer_type* packet) return 1; } -static void -xfrd_process_expire_option(buffer_type* packet, xfrd_zone_type* zone) -{ - size_t mempos = buffer_position(packet); - uint16_t rdlen; - - if(!zone->latest_xfr) - return; - - /* len(dname) + len(type) + len(class) + len(ttl) + len(rdlen) = - * 1 + 2 + 2 + 4 + 2 = 11 - * - * len(option_code) + len(option_len) + len(expire_option) = - * 2 + 2 + 4 = 8 - */ - if(!buffer_available(packet, 19) - || buffer_read_u8(packet) != 0 - || buffer_read_u16(packet) != TYPE_OPT) { - buffer_set_position(packet, mempos); - return; - } - /* skip UDP payload, rcode, version, flags (or class and ttl) */ - buffer_skip(packet, 6); - rdlen = buffer_read_u16(packet); - while(rdlen >= 8) { - uint16_t option_code, option_len; - - if(!buffer_available(packet, 8)) - break; - option_code = buffer_read_u16(packet); - option_len = buffer_read_u16(packet); - rdlen -= 4; - if(option_code == EXPIRE_CODE && option_len == 4) { - zone->latest_xfr->msg_has_expire_option = 1; - zone->latest_xfr->msg_expire_option_value = - buffer_read_u32(packet); - log_msg(LOG_INFO, "expire option set to %d for zone %s" - , (int)zone->latest_xfr->msg_expire_option_value - , zone->apex_str); - break; - } - /* skip option */ - if (option_len > rdlen - || !buffer_available(packet, option_len)) - break; - buffer_skip(packet, option_len); - rdlen -= option_len; - } - buffer_set_position(packet, mempos); -} - - static time_t xfrd_time_adjusted_for_expire_option_value(xfrd_zone_type* zone) { @@ -2343,8 +2291,10 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, if(!packet_skip_rr(packet, 0)) break; } - if(i == 0) { - xfrd_process_expire_option(packet, zone); + if(i == 0 && zone->latest_xfr) { + zone->latest_xfr->msg_has_expire_option + = process_expire_option(packet, + &zone->latest_xfr->msg_expire_option_value); } } /* (even if notified) the lease on the current soa is renewed */ @@ -2423,8 +2373,10 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, if(!packet_skip_rr(packet, 0)) break; } - if(i == 0) { - xfrd_process_expire_option(packet, zone); + if(i == 0 && zone->latest_xfr) { + zone->latest_xfr->msg_has_expire_option + = process_expire_option(packet, + &zone->latest_xfr->msg_expire_option_value); } } region_destroy(tempregion); From b1678e2c15204f3b300a6f1c76ec83cb6719e4a1 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 30 Aug 2024 15:29:47 +0200 Subject: [PATCH 4/4] Introduce refresh zone task So the expire option can return a counter based on the last time the zone was considered fresh. --- difffile.c | 35 +++++++++++++++++++++++++++++++++++ difffile.h | 4 ++++ xfrd.c | 13 ++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/difffile.c b/difffile.c index eb4b26b2a..ec3f211d4 100644 --- a/difffile.c +++ b/difffile.c @@ -1880,6 +1880,24 @@ task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname, return 1; } +void +task_new_refresh(udb_base* udb, udb_ptr* last, const dname_type* dname, + uint64_t acquired) +{ + udb_ptr e; + + DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task refresh %s %d", + dname_to_string(dname, 0), (int)acquired)); + if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + +dname_total_size(dname), dname)) { + log_msg(LOG_ERR, "tasklist: out of space, cannot add refresh"); + return; + } + TASKLIST(&e)->task_type = task_refresh; + TASKLIST(&e)->yesno = acquired; + udb_ptr_unlink(&e, udb); +} + void task_process_expire(namedb_type* db, struct task_list_d* task) { @@ -2162,6 +2180,20 @@ task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, fclose(df); } +static void +task_process_refresh(struct nsd* nsd, struct task_list_d* task) +{ + zone_type* zone; + + DEBUG(DEBUG_IPC,1, (LOG_INFO, "refresh task %s %d", dname_to_string( + task->zname, NULL), (int)task->yesno)); + zone = namedb_find_zone(nsd->db, task->zname); + if(!zone) + return; + + zone->mtime.tv_sec = task->yesno; + zone->mtime.tv_nsec = 0; +} void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task) @@ -2217,6 +2249,9 @@ void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, case task_activate_cookie_secret: task_process_activate_cookie_secret(nsd, TASKLIST(task)); break; + case task_refresh: + task_process_refresh(nsd, TASKLIST(task)); + break; default: log_msg(LOG_WARNING, "unhandled task in reload type %d", (int)TASKLIST(task)->task_type); diff --git a/difffile.h b/difffile.h index 4a88d4b1d..ed4eaa5b8 100644 --- a/difffile.h +++ b/difffile.h @@ -117,6 +117,8 @@ struct task_list_d { task_drop_cookie_secret, /** make staging cookie secret active */ task_activate_cookie_secret, + /** refresh a zone (set mtime to value of yesno) */ + task_refresh, } task_type; uint32_t size; /* size of this struct */ @@ -157,6 +159,8 @@ void task_new_drop_cookie_secret(udb_base* udb, udb_ptr* last); void task_new_activate_cookie_secret(udb_base* udb, udb_ptr* last); int task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* zone, uint32_t old_serial, uint32_t new_serial, uint64_t filenumber); +void task_new_refresh(udb_base* udb, udb_ptr* last, const dname_type* zone, + uint64_t acquired); void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task); void task_process_expire(namedb_type* db, struct task_list_d* task); diff --git a/xfrd.c b/xfrd.c index 7188e960b..3b30ea8b2 100644 --- a/xfrd.c +++ b/xfrd.c @@ -1051,6 +1051,16 @@ xfrd_set_timer_refresh(xfrd_zone_type* zone) xfrd_set_timer(zone, within_refresh_bounds(zone, set > xfrd_time() ? set - xfrd_time() : XFRD_LOWERBOUND_REFRESH)); + +#if 0 + if(zone->soa_disk_acquired) { + task_new_refresh( xfrd->nsd->task[xfrd->nsd->mytask] + , xfrd->last_task + , zone->apex + , zone->soa_disk_acquired); + xfrd_set_reload_now(xfrd); + } +#endif } static void @@ -2391,7 +2401,8 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, if(done == 0) return xfrd_packet_more; if(zone->master->key_options) { - if(zone->latest_xfr->tsig.updates_since_last_prepare != 0) { + if(zone->latest_xfr + && zone->latest_xfr->tsig.updates_since_last_prepare != 0) { log_msg(LOG_INFO, "xfrd: last packet of reply has no " "TSIG"); return xfrd_packet_bad;