Merge in some commits from upstream..
authorbrad <brad@openbsd.org>
Thu, 18 Dec 2014 23:26:12 +0000 (23:26 +0000)
committerbrad <brad@openbsd.org>
Thu, 18 Dec 2014 23:26:12 +0000 (23:26 +0000)
- 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@

13 files changed:
usr.sbin/nsd/difffile.c
usr.sbin/nsd/dns.c
usr.sbin/nsd/dns.h
usr.sbin/nsd/namedb.c
usr.sbin/nsd/namedb.h
usr.sbin/nsd/nsd-control.8.in
usr.sbin/nsd/query.c
usr.sbin/nsd/remote.c
usr.sbin/nsd/server.c
usr.sbin/nsd/xfrd-disk.c
usr.sbin/nsd/xfrd.c
usr.sbin/nsd/xfrd.h
usr.sbin/nsd/zparser.y

index 5510714..c9c8026 100644 (file)
@@ -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);
                }
        }
index a54fc98..5d80f8a 100644 (file)
@@ -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 */
index 2b07347..077f00d 100644 (file)
@@ -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 */
 
index 4fb2367..b30e96b 100644 (file)
@@ -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;
        }
 }
index 76f78df..34cf9e2 100644 (file)
@@ -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);
 
index 2ee2e4c..f5aa2cb 100644 (file)
@@ -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 [<zone>]
 Force update slave zones that are hosted on this server.  Even if the
index d5afe78..f8cb1b4 100644 (file)
@@ -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:
index 759136c..82b4999 100644 (file)
@@ -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) {
index 22cfff7..0c8ca29 100644 (file)
@@ -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
index a095bbf..a2f3e8a 100644 (file)
@@ -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);
        }
 
index 0ea9ea6..54b9650 100644 (file)
@@ -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;
        }
 }
 
index 5c731f6..e29a0d5 100644 (file)
@@ -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);
 
index 4855784..f916a74 100644 (file)
@@ -67,7 +67,7 @@ nsec3_add_params(const char* hash_algo_str, const char* flag_str,
 %token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR
 %token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY
 %token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA
-%token <type> T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA
+%token <type> 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
     {