From 03739794338fecca6d43568785393dd5cbab400f Mon Sep 17 00:00:00 2001 From: brad Date: Thu, 18 Dec 2014 23:26:12 +0000 Subject: [PATCH] Merge in some commits from upstream.. - Fix that failure to add tcp to tcp base does not leak the socket. - Fixes for wildcard addition and deletion, speedup for some cases. - Fix that queries for noname CH TXT are REFUSED instead of nodata. - Fix #616: retry xfer for zones with no content after command. - Fix that expired zones stay expired after a server restart. - RFC 7344: CDS and CDNSKEY (read in). ok sthen@ --- usr.sbin/nsd/difffile.c | 20 +++++++++++++------- usr.sbin/nsd/dns.c | 11 ++++++++--- usr.sbin/nsd/dns.h | 2 ++ usr.sbin/nsd/namedb.c | 22 +++++++++++++++++++++- usr.sbin/nsd/namedb.h | 1 + usr.sbin/nsd/nsd-control.8.in | 4 +++- usr.sbin/nsd/query.c | 2 ++ usr.sbin/nsd/remote.c | 10 ++++++++-- usr.sbin/nsd/server.c | 14 +++++++++++--- usr.sbin/nsd/xfrd-disk.c | 4 ++++ usr.sbin/nsd/xfrd.c | 9 ++++++--- usr.sbin/nsd/xfrd.h | 3 +++ usr.sbin/nsd/zparser.y | 6 +++++- 13 files changed, 87 insertions(+), 21 deletions(-) diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index 5510714f364..c9c8026369e 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -236,8 +236,8 @@ has_data_below(domain_type* top) } /** check if domain with 0 rrsets has become empty (nonexist) */ -static void -rrset_zero_nonexist_check(domain_type* domain) +static domain_type* +rrset_zero_nonexist_check(domain_type* domain, domain_type* ce) { /* is the node now an empty node (completely deleted) */ if(domain->rrsets == 0) { @@ -248,13 +248,18 @@ rrset_zero_nonexist_check(domain_type* domain) /* nonexist this domain and all parent empty nonterminals */ domain_type* p = domain; while(p != NULL && p->rrsets == 0) { - if(has_data_below(p)) - break; + if(p == ce || has_data_below(p)) + return p; p->is_existing = 0; + /* fixup wildcard child of parent */ + if(p->parent && + p->parent->wildcard_child_closest_match == p) + p->parent->wildcard_child_closest_match = domain_previous_existing_child(p); p = p->parent; } } } + return NULL; } /** remove rrset. Adjusts zone params. Does not remove domain */ @@ -682,7 +687,7 @@ delete_RR(namedb_type* db, const dname_type* dname, /* delete entire rrset */ rrset_delete(db, domain, rrset); /* check if domain is now nonexisting (or parents) */ - rrset_zero_nonexist_check(domain); + rrset_zero_nonexist_check(domain, NULL); #ifdef NSEC3 /* cleanup nsec3 */ nsec3_delete_rrset_trigger(db, domain, zone, type); @@ -914,9 +919,10 @@ delete_zone_rrs(namedb_type* db, zone_type* zone) domain = next; } - /* check if data deleteions have created nonexisting domain entries, + /* check if data deletions have created nonexisting domain entries, * but after deleting domains so the checks are faster */ if(nonexist_check) { + domain_type* ce = NULL; /* for speeding up has_data_below */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check")); domain = zone->apex; while(domain && domain_is_subdomain(domain, zone->apex)) @@ -926,7 +932,7 @@ delete_zone_rrs(namedb_type* db, zone_type* zone) * sub-zones, since we only spuriously check empty * nonterminals */ if(domain->is_existing) - rrset_zero_nonexist_check(domain); + ce = rrset_zero_nonexist_check(domain, ce); domain = domain_next(domain); } } diff --git a/usr.sbin/nsd/dns.c b/usr.sbin/nsd/dns.c index a54fc9871c0..5d80f8a11ba 100644 --- a/usr.sbin/nsd/dns.c +++ b/usr.sbin/nsd/dns.c @@ -289,9 +289,14 @@ static rrtype_descriptor_type rrtype_descriptors[(RRTYPE_DESCRIPTORS_LENGTH+1)] /* 58 - TALINK */ { 58, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 59 - CDS */ - { 59, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, - /* 60 */ - { 60, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, + { TYPE_CDS, "CDS", T_CDS, 4, 4, + { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, + { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, + /* 60 - CDNSKEY */ + { TYPE_CDNSKEY, "CDNSKEY", T_CDNSKEY, 4, 4, + { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, + { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, + RDATA_ZF_BASE64 } }, /* 61 */ { 61, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 62 */ diff --git a/usr.sbin/nsd/dns.h b/usr.sbin/nsd/dns.h index 2b0734764ec..077f00d2f27 100644 --- a/usr.sbin/nsd/dns.h +++ b/usr.sbin/nsd/dns.h @@ -136,6 +136,8 @@ typedef enum nsd_rc nsd_rc_type; #define TYPE_NSEC3 50 /* NSEC3, secure denial, prevents zonewalking */ #define TYPE_NSEC3PARAM 51 /* NSEC3PARAM at zone apex nsec3 parameters */ #define TYPE_TLSA 52 /* RFC 6698 */ +#define TYPE_CDS 59 /* RFC 7344 */ +#define TYPE_CDNSKEY 60 /* RFC 7344 */ #define TYPE_SPF 99 /* RFC 4408 */ diff --git a/usr.sbin/nsd/namedb.c b/usr.sbin/nsd/namedb.c index 4fb23671550..b30e96b01c7 100644 --- a/usr.sbin/nsd/namedb.c +++ b/usr.sbin/nsd/namedb.c @@ -249,7 +249,7 @@ do_deldomain(namedb_type* db, domain_type* domain) * one-smaller than this domain as closest-match. */ if(domain->parent->wildcard_child_closest_match == domain) domain->parent->wildcard_child_closest_match = - domain_previous(domain); + domain_previous_existing_child(domain); /* actual removal */ radix_delete(db->domains->nametree, domain->rnode); @@ -456,6 +456,17 @@ domain_table_iterate(domain_table_type* table, return error; } +domain_type *domain_previous_existing_child(domain_type* domain) +{ + domain_type* parent = domain->parent; + domain = domain_previous(domain); + while(domain && !domain->is_existing) { + if(domain == parent) /* do not walk back above parent */ + return parent; + domain = domain_previous(domain); + } + return domain; +} void domain_add_rrset(domain_type* domain, rrset_type* rrset) @@ -474,6 +485,15 @@ domain_add_rrset(domain_type* domain, rrset_type* rrset) while (domain && !domain->is_existing) { domain->is_existing = 1; + /* does this name in existance update the parent's + * wildcard closest match? */ + if(domain->parent + && label_compare(dname_name(domain_dname(domain)), + (const uint8_t *) "\001*") <= 0 + && dname_compare(domain_dname(domain), + domain_dname(domain->parent->wildcard_child_closest_match)) > 0) { + domain->parent->wildcard_child_closest_match = domain; + } domain = domain->parent; } } diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index 76f78dfa648..34cf9e288bd 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -250,6 +250,7 @@ int domain_is_glue(domain_type* domain, zone_type* zone); rrset_type* domain_find_non_cname_rrset(domain_type* domain, zone_type* zone); domain_type* domain_wildcard_child(domain_type* domain); +domain_type *domain_previous_existing_child(domain_type* domain); int zone_is_secure(zone_type* zone); diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index 2ee2e4c8d0a..f5aa2cbe4e4 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -108,7 +108,9 @@ Attempt to update slave zones that are hosted on this server by contacting the masters. The masters are configured via 'request\-xfr:' lists. If a zone is given, that zone is updated. Usually NSD receives a NOTIFY from the masters (configured via 'allow\-notify:' acl list) that a new zone -serial has to be transferred. +serial has to be transferred. For zones with no content, NSD may have backed +off from asking often because the masters did not respond, but this command +will reset the backoff to its initial timeout, for frequent retries. .TP .B force_transfer [] Force update slave zones that are hosted on this server. Even if the diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index d5afe789cf0..f8cb1b496c0 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -528,6 +528,8 @@ answer_chaos(struct nsd *nsd, query_type *q) } else { RCODE_SET(q->packet, RCODE_REFUSE); } + } else { + RCODE_SET(q->packet, RCODE_REFUSE); } break; default: diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index 759136c9645..82b49990216 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -567,10 +567,16 @@ remote_accept_callback(int fd, short event, void* arg) event_set(&n->c, newfd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, n); - if(event_base_set(xfrd->event_base, &n->c) != 0) + if(event_base_set(xfrd->event_base, &n->c) != 0) { log_msg(LOG_ERR, "remote_accept: cannot set event_base"); - if(event_add(&n->c, &n->tval) != 0) + free(n); + goto close_exit; + } + if(event_add(&n->c, &n->tval) != 0) { log_msg(LOG_ERR, "remote_accept: cannot add event"); + free(n); + goto close_exit; + } n->event_added = 1; if(2 <= verbosity) { diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index 22cfff7897c..0c8ca29c754 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -2522,10 +2522,18 @@ handle_tcp_accept(int fd, short event, void* arg) event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, tcp_data); - if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) - log_msg(LOG_ERR, "cannot set tcp event base"); - if(event_add(&tcp_data->event, &timeout) != 0) + if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) { log_msg(LOG_ERR, "cannot set tcp event base"); + close(s); + region_destroy(tcp_region); + return; + } + if(event_add(&tcp_data->event, &timeout) != 0) { + log_msg(LOG_ERR, "cannot add tcp to event base"); + close(s); + region_destroy(tcp_region); + return; + } /* * Keep track of the total number of TCP handlers installed so diff --git a/usr.sbin/nsd/xfrd-disk.c b/usr.sbin/nsd/xfrd-disk.c index a095bbfacf9..a2f3e8af01d 100644 --- a/usr.sbin/nsd/xfrd-disk.c +++ b/usr.sbin/nsd/xfrd-disk.c @@ -308,6 +308,10 @@ xfrd_read_state(struct xfrd_state* xfrd) * contents trumps the contents of this cache */ /* zone->soa_disk_acquired = soa_disk_acquired_read; */ zone->soa_notified_acquired = soa_notified_acquired_read; + if (zone->state == xfrd_zone_expired) + { + xfrd_send_expire_notification(zone); + } xfrd_handle_incoming_soa(zone, &incoming_soa, incoming_acquired); } diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index 0ea9ea651d3..54b9650d458 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/xfrd.c @@ -76,8 +76,6 @@ static void xfrd_handle_reload(int fd, short event, void* arg); /* handle child timeout */ static void xfrd_handle_child_timer(int fd, short event, void* arg); -/* send expiry notifications to nsd */ -static void xfrd_send_expire_notification(xfrd_zone_t* zone); /* send ixfr request, returns fd of connection to read on */ static int xfrd_send_ixfr_request_udp(xfrd_zone_t* zone); /* obtain udp socket slot */ @@ -1147,7 +1145,7 @@ xfrd_handle_incoming_soa(xfrd_zone_t* zone, xfrd_send_notify(xfrd->notify_zones, zone->apex, &zone->soa_nsd); } -static void +void xfrd_send_expire_notification(xfrd_zone_t* zone) { task_new_expire(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, @@ -2087,6 +2085,11 @@ xfrd_handle_notify_and_start_xfr(xfrd_zone_t* zone, xfrd_soa_t* soa) !zone->tcp_waiting && !zone->udp_waiting) { xfrd_set_refresh_now(zone); } + /* zones with no content start expbackoff again; this is also + * for nsd-control started transfer commands, and also when + * the master apparantly sends notifies (is back up) */ + if(zone->soa_disk_acquired == 0) + zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; } } diff --git a/usr.sbin/nsd/xfrd.h b/usr.sbin/nsd/xfrd.h index 5c731f6c085..e29a0d52e97 100644 --- a/usr.sbin/nsd/xfrd.h +++ b/usr.sbin/nsd/xfrd.h @@ -342,6 +342,9 @@ void xfrd_process_task_result(xfrd_state_t* xfrd, struct udb_base* taskudb); /* set to reload right away (for user controlled reload events) */ void xfrd_set_reload_now(xfrd_state_t* xfrd); +/* send expiry notifications to nsd */ +void xfrd_send_expire_notification(xfrd_zone_t* zone); + /* handle incoming notify (soa or NULL) and start zone xfr if necessary */ void xfrd_handle_notify_and_start_xfr(xfrd_zone_t* zone, xfrd_soa_t* soa); diff --git a/usr.sbin/nsd/zparser.y b/usr.sbin/nsd/zparser.y index 4855784f7e2..f916a74d936 100644 --- a/usr.sbin/nsd/zparser.y +++ b/usr.sbin/nsd/zparser.y @@ -67,7 +67,7 @@ nsec3_add_params(const char* hash_algo_str, const char* flag_str, %token T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR %token T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY %token T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA -%token T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA +%token T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY /* other tokens */ %token DOLLAR_TTL DOLLAR_ORIGIN NL SP @@ -612,6 +612,10 @@ type_and_rdata: | T_EUI64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CAA sp rdata_caa | T_CAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_CDS sp rdata_ds + | T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_CDNSKEY sp rdata_dnskey + | T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | STR error NL { -- 2.20.1