From: florian Date: Sat, 3 Feb 2018 11:03:51 +0000 (+0000) Subject: Update nsd to 4.1.19. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ee5153b76e0db0e530220bd4ec0e249a51365081;p=openbsd Update nsd to 4.1.19. OK sthen@, "so far so good" millert@ Obligatory commit from 33,000 ft. --- diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in index 495160c0826..3468101c19d 100644 --- a/usr.sbin/nsd/Makefile.in +++ b/usr.sbin/nsd/Makefile.in @@ -286,9 +286,6 @@ qtest.o: $(srcdir)/tpkg/cutest/qtest.c udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c $(COMPILE) -c $(srcdir)/tpkg/cutest/udb-inspect.c -xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c - $(COMPILE) -c $(srcdir)/tpkg/cutest/xfr-inspect.c - zlexer.c: $(srcdir)/zlexer.lex if test "$(LEX)" != ":"; then rm -f $@ ;\ echo '#include "config.h"' > $@ ;\ @@ -516,7 +513,7 @@ udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c config.h $(srcdir)/udb.h $(sr $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \ $(srcdir)/namedb.h $(srcdir)/difffile.h $(srcdir)/options.h config.h -xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \ +xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \ $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/namedb.h $(srcdir)/difffile.h \ $(srcdir)/options.h config.h diff --git a/usr.sbin/nsd/axfr.c b/usr.sbin/nsd/axfr.c index 6f6b0957e99..dd34c0c3cee 100644 --- a/usr.sbin/nsd/axfr.c +++ b/usr.sbin/nsd/axfr.c @@ -201,6 +201,7 @@ answer_axfr_ixfr(struct nsd *nsd, struct query *q) return query_axfr(nsd, q); } /** Fallthrough: AXFR over UDP queries are discarded. */ + /* fallthrough */ case TYPE_IXFR: RCODE_SET(q->packet, RCODE_IMPL); return QUERY_PROCESSED; diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index dfef60dccc7..1fb5bda0003 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -478,7 +478,8 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) /* see if the domain is no longer precompiled */ /* it has a hash_node, but no longer fulfills conditions */ if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 && - domain->nsec3->hash_node.key && + domain->nsec3->hash_wc && + domain->nsec3->hash_wc->hash.node.key && !nsec3_condition_hash(domain, zone)) { /* remove precompile */ domain->nsec3->nsec3_cover = NULL; @@ -486,12 +487,13 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) domain->nsec3->nsec3_is_exact = 0; /* remove it from the hash tree */ zone_del_domain_in_hash_tree(zone->hashtree, - &domain->nsec3->hash_node); + &domain->nsec3->hash_wc->hash.node); zone_del_domain_in_hash_tree(zone->wchashtree, - &domain->nsec3->wchash_node); + &domain->nsec3->hash_wc->wc.node); } if(domain != zone->apex && domain->nsec3 && - domain->nsec3->dshash_node.key && + domain->nsec3->ds_parent_hash && + domain->nsec3->ds_parent_hash->node.key && (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) && !nsec3_condition_dshash(domain, zone)) { /* remove precompile */ @@ -499,7 +501,7 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) domain->nsec3->nsec3_ds_parent_is_exact = 0; /* remove it from the hash tree */ zone_del_domain_in_hash_tree(zone->dshashtree, - &domain->nsec3->dshash_node); + &domain->nsec3->ds_parent_hash->node); } } @@ -510,13 +512,15 @@ nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain, { if(!zone->nsec3_param) return; - if((!domain->nsec3 || !domain->nsec3->hash_node.key) + if((!domain->nsec3 || !domain->nsec3->hash_wc + || !domain->nsec3->hash_wc->hash.node.key) && nsec3_condition_hash(domain, zone)) { region_type* tmpregion = region_create(xalloc, free); nsec3_precompile_domain(db, domain, zone, tmpregion); region_destroy(tmpregion); } - if((!domain->nsec3 || !domain->nsec3->dshash_node.key) + if((!domain->nsec3 || !domain->nsec3->ds_parent_hash + || !domain->nsec3->ds_parent_hash->node.key) && nsec3_condition_dshash(domain, zone)) { nsec3_precompile_domain_ds(db, domain, zone); } diff --git a/usr.sbin/nsd/lookup3.c b/usr.sbin/nsd/lookup3.c index e0179f06d29..9602ffa374b 100644 --- a/usr.sbin/nsd/lookup3.c +++ b/usr.sbin/nsd/lookup3.c @@ -5,6 +5,7 @@ added #ifdef VALGRIND to remove 298,384,660 'unused variable k8' warnings. added include of lookup3.h to check definitions match declarations. removed include of stdint - config.h takes care of platform independence. + added fallthrough comments for new gcc warning suppression. url http://burtleburtle.net/bob/hash/index.html. */ /* @@ -235,7 +236,9 @@ uint32_t initval) /* the previous hash, or an arbitrary value */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; + /* fallthrough */ case 2 : b+=k[1]; + /* fallthrough */ case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ @@ -473,16 +476,27 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval) switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; + /* fallthrough */ case 11: c+=((uint32_t)k[10])<<16; + /* fallthrough */ case 10: c+=((uint32_t)k[9])<<8; + /* fallthrough */ case 9 : c+=k[8]; + /* fallthrough */ case 8 : b+=((uint32_t)k[7])<<24; + /* fallthrough */ case 7 : b+=((uint32_t)k[6])<<16; + /* fallthrough */ case 6 : b+=((uint32_t)k[5])<<8; + /* fallthrough */ case 5 : b+=k[4]; + /* fallthrough */ case 4 : a+=((uint32_t)k[3])<<24; + /* fallthrough */ case 3 : a+=((uint32_t)k[2])<<16; + /* fallthrough */ case 2 : a+=((uint32_t)k[1])<<8; + /* fallthrough */ case 1 : a+=k[0]; break; case 0 : return c; diff --git a/usr.sbin/nsd/namedb.c b/usr.sbin/nsd/namedb.c index bcc41aad926..bc7690d87b6 100644 --- a/usr.sbin/nsd/namedb.c +++ b/usr.sbin/nsd/namedb.c @@ -73,15 +73,11 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result) result->nsec3->nsec3_ds_parent_cover = NULL; result->nsec3->nsec3_is_exact = 0; result->nsec3->nsec3_ds_parent_is_exact = 0; - result->nsec3->have_nsec3_hash = 0; - result->nsec3->have_nsec3_wc_hash = 0; - result->nsec3->have_nsec3_ds_parent_hash = 0; + result->nsec3->hash_wc = NULL; + result->nsec3->ds_parent_hash = NULL; result->nsec3->prehash_prev = NULL; result->nsec3->prehash_next = NULL; result->nsec3->nsec3_node.key = NULL; - result->nsec3->hash_node.key = NULL; - result->nsec3->wchash_node.key = NULL; - result->nsec3->dshash_node.key = NULL; } #endif /* NSEC3 */ @@ -89,7 +85,7 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result) static void numlist_make_last(domain_table_type* table, domain_type* domain) { - size_t sw; + uint32_t sw; domain_type* last = table->numlist_last; if(domain == last) return; @@ -235,15 +231,17 @@ do_deldomain(namedb_type* db, domain_type* domain) if(domain->nsec3->nsec3_node.key) zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) ->nsec3tree, &domain->nsec3->nsec3_node); - if(domain->nsec3->hash_node.key) - zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) - ->hashtree, &domain->nsec3->hash_node); - if(domain->nsec3->wchash_node.key) - zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) - ->wchashtree, &domain->nsec3->wchash_node); - if(domain->nsec3->dshash_node.key) + if(domain->nsec3->hash_wc) { + if(domain->nsec3->hash_wc->hash.node.key) + zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) + ->hashtree, &domain->nsec3->hash_wc->hash.node); + if(domain->nsec3->hash_wc->wc.node.key) + zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain) + ->wchashtree, &domain->nsec3->hash_wc->wc.node); + } + if(domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key) zone_del_domain_in_hash_tree(nsec3_tree_dszone(db, domain) - ->dshashtree, &domain->nsec3->dshash_node); + ->dshashtree, &domain->nsec3->ds_parent_hash->node); region_recycle(db->domains->region, domain->nsec3, sizeof(struct nsec3_domain_data)); } diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index e2d84517854..c7cf6d96802 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -53,6 +53,20 @@ struct domain_table }; #ifdef NSEC3 +typedef struct nsec3_hash_node nsec3_hash_node_type; +struct nsec3_hash_node { + /* hash value */ + uint8_t hash[NSEC3_HASH_LEN]; + /* entry in the hashtree */ + rbnode_type node; +} ATTR_PACKED; + +typedef struct nsec3_hash_wc_node nsec3_hash_wc_node_type; +struct nsec3_hash_wc_node { + nsec3_hash_node_type hash; + nsec3_hash_node_type wc; +}; + struct nsec3_domain_data { /* (if nsec3 chain complete) always the covering nsec3 record */ domain_type* nsec3_cover; @@ -64,28 +78,18 @@ struct nsec3_domain_data { domain_type* prehash_prev, *prehash_next; /* entry in the nsec3tree (for NSEC3s in the chain in use) */ rbnode_type nsec3_node; - /* entry in the hashtree (for precompiled domains) */ - rbnode_type hash_node; - /* entry in the wchashtree (the wildcard precompile) */ - rbnode_type wchash_node; - /* entry in the dshashtree (the parent ds precompile) */ - rbnode_type dshash_node; - - /* nsec3 hash */ - uint8_t nsec3_hash[NSEC3_HASH_LEN]; - /* nsec3 hash of wildcard before this name */ - uint8_t nsec3_wc_hash[NSEC3_HASH_LEN]; - /* parent-side DS hash */ - uint8_t nsec3_ds_parent_hash[NSEC3_HASH_LEN]; - /* if the nsec3 has is available */ - unsigned have_nsec3_hash : 1; - unsigned have_nsec3_wc_hash : 1; - unsigned have_nsec3_ds_parent_hash : 1; + + /* node for the precompiled domain and the precompiled wildcard */ + nsec3_hash_wc_node_type* hash_wc; + + /* node for the precompiled parent ds */ + nsec3_hash_node_type* ds_parent_hash; + /* if the domain has an NSEC3 for it, use cover ptr to get it. */ unsigned nsec3_is_exact : 1; /* same but on parent side */ unsigned nsec3_ds_parent_is_exact : 1; -}; +} ATTR_PACKED; #endif /* NSEC3 */ struct domain @@ -104,8 +108,8 @@ struct domain #endif /* double-linked list sorted by domain.number */ domain_type* numlist_prev, *numlist_next; - size_t number; /* Unique domain name number. */ - size_t usage; /* number of ptrs to this from RRs(in rdata) and + uint32_t number; /* Unique domain name number. */ + uint32_t usage; /* number of ptrs to this from RRs(in rdata) and from zone-apex pointers, also the root has one more to make sure it cannot be deleted. */ @@ -114,7 +118,7 @@ struct domain */ unsigned is_existing : 1; unsigned is_apex : 1; -}; +} ATTR_PACKED; struct zone { @@ -140,7 +144,7 @@ struct zone unsigned is_secure : 1; /* zone uses DNSSEC */ unsigned is_ok : 1; /* zone has not expired. */ unsigned is_changed : 1; /* zone was changed by AXFR */ -}; +} ATTR_PACKED; /* a RR in DNS */ struct rr { @@ -150,7 +154,7 @@ struct rr { uint16_t type; uint16_t klass; uint16_t rdata_count; -}; +} ATTR_PACKED; /* * An RRset consists of at least one RR. All RRs are from the same @@ -162,7 +166,7 @@ struct rrset zone_type* zone; rr_type* rrs; uint16_t rr_count; -}; +} ATTR_PACKED; /* * The field used is based on the wireformat the atom is stored in. diff --git a/usr.sbin/nsd/netio.c b/usr.sbin/nsd/netio.c index 6c4b395babe..58fd2e18b49 100644 --- a/usr.sbin/nsd/netio.c +++ b/usr.sbin/nsd/netio.c @@ -94,7 +94,7 @@ netio_current_time(netio_type *netio) if (!netio->have_current_time) { struct timeval current_timeval; if (gettimeofday(¤t_timeval, NULL) == -1) { - log_msg(LOG_CRIT, "gettimeofday: %s, aborting.", strerror(errno)); + log_msg(LOG_ERR, "gettimeofday: %s, aborting.", strerror(errno)); abort(); } timeval_to_timespec(&netio->cached_current_time, ¤t_timeval); diff --git a/usr.sbin/nsd/nsd.c b/usr.sbin/nsd/nsd.c index f2cf6ccf0cb..dfbc58696b3 100644 --- a/usr.sbin/nsd/nsd.c +++ b/usr.sbin/nsd/nsd.c @@ -579,6 +579,7 @@ main(int argc, char *argv[]) case 'v': version(); /* version exits */ + break; #ifndef NDEBUG case 'F': sscanf(optarg, "%x", &nsd_debug_facilities); @@ -980,6 +981,7 @@ main(int argc, char *argv[]) break; case -1: error("fork() failed: %s", strerror(errno)); + break; default: /* Parent is done */ server_close_all_sockets(nsd.udp, nsd.ifs); diff --git a/usr.sbin/nsd/nsec3.c b/usr.sbin/nsd/nsec3.c index 960e7216dad..dad4f23d7bf 100644 --- a/usr.sbin/nsd/nsec3.c +++ b/usr.sbin/nsd/nsec3.c @@ -29,8 +29,10 @@ cmp_hash_tree(const void* x, const void* y) const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; - return memcmp(a->nsec3->nsec3_hash, b->nsec3->nsec3_hash, - NSEC3_HASH_LEN); + if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); + if(!b->nsec3->hash_wc) return 1; + return memcmp(a->nsec3->hash_wc->hash.hash, + b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN); } /* compare nsec3 hashes in nsec3 wc tree */ @@ -41,8 +43,10 @@ cmp_wchash_tree(const void* x, const void* y) const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; - return memcmp(a->nsec3->nsec3_wc_hash, b->nsec3->nsec3_wc_hash, - NSEC3_HASH_LEN); + if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0); + if(!b->nsec3->hash_wc) return 1; + return memcmp(a->nsec3->hash_wc->wc.hash, + b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN); } /* compare nsec3 hashes in nsec3 ds tree */ @@ -53,8 +57,10 @@ cmp_dshash_tree(const void* x, const void* y) const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; - return memcmp(a->nsec3->nsec3_ds_parent_hash, - b->nsec3->nsec3_ds_parent_hash, NSEC3_HASH_LEN); + if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0); + if(!b->nsec3->ds_parent_hash) return 1; + return memcmp(a->nsec3->ds_parent_hash->hash, + b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN); } /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are @@ -129,32 +135,36 @@ nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store) /** find hash or create it and store it */ static void -nsec3_lookup_hash_and_wc(zone_type* zone, const dname_type* dname, - domain_type* domain, region_type* tmpregion) +nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone, + const dname_type* dname, domain_type* domain, region_type* tmpregion) { const dname_type* wcard; - if(domain->nsec3->have_nsec3_hash && domain->nsec3->have_nsec3_wc_hash) { + if(domain->nsec3->hash_wc) { return; } /* lookup failed; disk failure or so */ - nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_hash); - domain->nsec3->have_nsec3_hash = 1; + domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *) + region_alloc(region, sizeof(nsec3_hash_wc_node_type)); + domain->nsec3->hash_wc->hash.node.key = NULL; + domain->nsec3->hash_wc->wc.node.key = NULL; + nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash); wcard = dname_parse(tmpregion, "*"); wcard = dname_concatenate(tmpregion, wcard, dname); - nsec3_hash_and_store(zone, wcard, domain->nsec3->nsec3_wc_hash); - domain->nsec3->have_nsec3_wc_hash = 1; + nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash); } static void -nsec3_lookup_hash_ds(zone_type* zone, const dname_type* dname, - domain_type* domain) +nsec3_lookup_hash_ds(region_type* region, zone_type* zone, + const dname_type* dname, domain_type* domain) { - if(domain->nsec3->have_nsec3_ds_parent_hash) { + if(domain->nsec3->ds_parent_hash) { return; } /* lookup failed; disk failure or so */ - nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_ds_parent_hash); - domain->nsec3->have_nsec3_ds_parent_hash = 1; + domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *) + region_alloc(region, sizeof(nsec3_hash_node_type)); + domain->nsec3->ds_parent_hash->node.key = NULL; + nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash); } static int @@ -380,17 +390,23 @@ nsec3_clear_precompile(struct namedb* db, zone_type* zone) walk->nsec3->nsec3_cover = NULL; walk->nsec3->nsec3_wcard_child_cover = NULL; walk->nsec3->nsec3_is_exact = 0; - walk->nsec3->have_nsec3_hash = 0; - walk->nsec3->have_nsec3_wc_hash = 0; - walk->nsec3->hash_node.key = NULL; - walk->nsec3->wchash_node.key = NULL; + if (walk->nsec3->hash_wc) { + region_recycle(db->domains->region, + walk->nsec3->hash_wc, + sizeof(nsec3_hash_wc_node_type)); + walk->nsec3->hash_wc = NULL; + } } if(!walk->parent || nsec3_domain_part_of_zone(walk->parent, zone)) { walk->nsec3->nsec3_ds_parent_cover = NULL; walk->nsec3->nsec3_ds_parent_is_exact = 0; - walk->nsec3->have_nsec3_ds_parent_hash = 0; - walk->nsec3->dshash_node.key = NULL; + if (walk->nsec3->ds_parent_hash) { + region_recycle(db->domains->region, + walk->nsec3->ds_parent_hash, + sizeof(nsec3_hash_node_type)); + walk->nsec3->ds_parent_hash = NULL; + } } } walk = domain_next(walk); @@ -503,25 +519,26 @@ nsec3_precompile_domain(struct namedb* db, struct domain* domain, allocate_domain_nsec3(db->domains, domain); /* hash it */ - nsec3_lookup_hash_and_wc(zone, domain_dname(domain), domain, tmpregion); + nsec3_lookup_hash_and_wc(db->region, + zone, domain_dname(domain), domain, tmpregion); /* add into tree */ zone_add_domain_in_hash_tree(db->region, &zone->hashtree, - cmp_hash_tree, domain, &domain->nsec3->hash_node); + cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node); zone_add_domain_in_hash_tree(db->region, &zone->wchashtree, - cmp_wchash_tree, domain, &domain->nsec3->wchash_node); + cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node); /* lookup in tree cover ptr (or exact) */ - exact = nsec3_find_cover(zone, domain->nsec3->nsec3_hash, - sizeof(domain->nsec3->nsec3_hash), &result); + exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash, + sizeof(domain->nsec3->hash_wc->hash.hash), &result); domain->nsec3->nsec3_cover = result; if(exact) domain->nsec3->nsec3_is_exact = 1; else domain->nsec3->nsec3_is_exact = 0; /* find cover for *.domain for wildcard denial */ - exact = nsec3_find_cover(zone, domain->nsec3->nsec3_wc_hash, - sizeof(domain->nsec3->nsec3_wc_hash), &result); + exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash, + sizeof(domain->nsec3->hash_wc->wc.hash), &result); domain->nsec3->nsec3_wcard_child_cover = result; } @@ -535,17 +552,17 @@ nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, /* hash it : it could have different hash parameters then the other hash for this domain name */ - nsec3_lookup_hash_ds(zone, domain_dname(domain), domain); + nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain); /* lookup in tree cover ptr (or exact) */ - exact = nsec3_find_cover(zone, domain->nsec3->nsec3_ds_parent_hash, - sizeof(domain->nsec3->nsec3_ds_parent_hash), &result); + exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash, + sizeof(domain->nsec3->ds_parent_hash->hash), &result); if(exact) domain->nsec3->nsec3_ds_parent_is_exact = 1; else domain->nsec3->nsec3_ds_parent_is_exact = 0; domain->nsec3->nsec3_ds_parent_cover = result; /* add into tree */ zone_add_domain_in_hash_tree(db->region, &zone->dshashtree, - cmp_dshash_tree, domain, &domain->nsec3->dshash_node); + cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node); } static void @@ -644,15 +661,15 @@ prehash_zone_complete(struct namedb* db, struct zone* zone) static void init_lookup_key_hash_tree(domain_type* d, uint8_t* hash) -{ memcpy(d->nsec3->nsec3_hash, hash, NSEC3_HASH_LEN); } +{ memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); } static void init_lookup_key_wc_tree(domain_type* d, uint8_t* hash) -{ memcpy(d->nsec3->nsec3_wc_hash, hash, NSEC3_HASH_LEN); } +{ memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); } static void init_lookup_key_ds_tree(domain_type* d, uint8_t* hash) -{ memcpy(d->nsec3->nsec3_ds_parent_hash, hash, NSEC3_HASH_LEN); } +{ memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); } /* find first in the tree and true if the first to process it */ static int @@ -661,10 +678,18 @@ process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p, { domain_type d; struct nsec3_domain_data n; + nsec3_hash_wc_node_type hash_wc; + nsec3_hash_node_type ds_parent_hash; + if(!tree) { *p = RBTREE_NULL; return 0; } + hash_wc.hash.node.key = NULL; + hash_wc.wc.node.key = NULL; + n.hash_wc = &hash_wc; + ds_parent_hash.node.key = NULL; + n.ds_parent_hash = &ds_parent_hash; d.nsec3 = &n; init(&d, hash); if(rbtree_find_less_equal(tree, &d, p)) { @@ -687,10 +712,18 @@ process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p, { domain_type d; struct nsec3_domain_data n; + nsec3_hash_wc_node_type hash_wc; + nsec3_hash_node_type ds_parent_hash; + if(!tree) { *p = RBTREE_NULL; return; } + hash_wc.hash.node.key = NULL; + hash_wc.wc.node.key = NULL; + n.hash_wc = &hash_wc; + ds_parent_hash.node.key = NULL; + n.ds_parent_hash = &ds_parent_hash; d.nsec3 = &n; init(&d, hash); if(rbtree_find_less_equal(tree, &d, p)) { @@ -854,9 +887,34 @@ nsec3_add_nonexist_proof(struct query* query, struct answer* answer, if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover)) { /* exact match, hash collision */ + domain_type* walk; + char hashbuf[512]; + char reversebuf[512]; + (void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf)); + snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)"); + walk = query->zone->apex; + while(walk) { + if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) { + snprintf(reversebuf, sizeof(reversebuf), + "%s %s", domain_to_string(walk), + walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match"); + if(walk->nsec3->nsec3_is_exact) + break; + } + if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) { + snprintf(reversebuf, sizeof(reversebuf), + "%s %s", domain_to_string(walk), + walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match"); + if(walk->nsec3->nsec3_ds_parent_is_exact) + break; + } + walk = domain_next(walk); + } + + /* the hashed name of the query corresponds to an existing name. */ - VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s", - dname_to_string(to_prove, NULL))); + VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s", + dname_to_string(to_prove, NULL), hashbuf, reversebuf)); RCODE_SET(query->packet, RCODE_SERVFAIL); return; } diff --git a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h index dedb9bfb662..bbfbbf98c41 100644 --- a/usr.sbin/nsd/options.h +++ b/usr.sbin/nsd/options.h @@ -165,7 +165,7 @@ struct pattern_options { uint8_t min_retry_time_is_default; uint64_t size_limit_xfr; uint8_t multi_master_check; -}; +} ATTR_PACKED; #define PATTERN_IMPLICIT_MARKER "_implicit_" @@ -186,7 +186,7 @@ struct zone_options { struct pattern_options* pattern; /* zone is fixed into the main config, not in zonelist, cannot delete */ uint8_t part_of_config; -}; +} ATTR_PACKED; union acl_addr_storage { #ifdef INET6 @@ -227,7 +227,7 @@ struct acl_options { uint8_t blocked; const char* key_name; struct key_options* key_options; -}; +} ATTR_PACKED; /* * Key definition @@ -238,7 +238,7 @@ struct key_options { char* algorithm; char* secret; struct tsig_key* tsig_key; -}; +} ATTR_PACKED; /** zone list free space */ struct zonelist_free { diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index d6e45a2e9d3..7b862a45bc7 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -1241,8 +1241,15 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, * authoritative for the parent zone. */ zone_type *zone = domain_find_parent_zone(nsd->db, q->zone); - if (zone) + if (zone) { q->zone = zone; + if(!q->zone->apex || !q->zone->soa_rrset) { + /* zone is configured but not loaded */ + if(q->cname_count == 0) + RCODE_SET(q->packet, RCODE_SERVFAIL); + return; + } + } } /* see if the zone has expired (for secondary zones) */ diff --git a/usr.sbin/nsd/radtree.h b/usr.sbin/nsd/radtree.h index fdc58e7a903..c5d830a138b 100644 --- a/usr.sbin/nsd/radtree.h +++ b/usr.sbin/nsd/radtree.h @@ -49,7 +49,7 @@ struct radnode { uint16_t capacity; /** the lookup array by [byte-offset] */ struct radsel* array; -}; +} ATTR_PACKED; /** * radix select edge in array @@ -61,7 +61,7 @@ struct radsel { radstrlen_type len; /** node that deals with byte+str */ struct radnode* node; -}; +} ATTR_PACKED; /** * Create new radix tree diff --git a/usr.sbin/nsd/rbtree.h b/usr.sbin/nsd/rbtree.h index d6e54862a23..eb9b3941245 100644 --- a/usr.sbin/nsd/rbtree.h +++ b/usr.sbin/nsd/rbtree.h @@ -24,7 +24,7 @@ struct rbnode { rbnode_type *right; const void *key; uint8_t color; -}; +} ATTR_PACKED; #define RBTREE_NULL &rbtree_null_node extern rbnode_type rbtree_null_node; @@ -44,7 +44,7 @@ struct rbtree { /* Key compare function. <0,0,>0 like strcmp. Return 0 on two NULL ptrs. */ int (*cmp) (const void *, const void *); -}; +} ATTR_PACKED; /* rbtree.c */ rbtree_type *rbtree_create(region_type *region, int (*cmpf)(const void *, const void *)); diff --git a/usr.sbin/nsd/region-allocator.c b/usr.sbin/nsd/region-allocator.c index 95454a66678..8b5d2c77989 100644 --- a/usr.sbin/nsd/region-allocator.c +++ b/usr.sbin/nsd/region-allocator.c @@ -23,12 +23,17 @@ #ifdef ALIGNMENT #undef ALIGNMENT #endif +#ifndef PACKED_STRUCTS #define REGION_ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1))) #if SIZEOF_OFF_T > SIZEOF_VOIDP #define ALIGNMENT (sizeof(off_t)) #else #define ALIGNMENT (sizeof(void *)) #endif +#else +#define REGION_ALIGN_UP(x, s) ((x)chunk_size - region->allocated) & (~(ALIGNMENT-1)); - if(wasted >= ALIGNMENT) { + if( +#ifndef PACKED_STRUCTS + wasted >= ALIGNMENT +#else + wasted >= SIZEOF_VOIDP +#endif + ) { /* put wasted part in recycle bin for later use */ region->total_allocated += wasted; ++region->small_objects; diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index f7c88222b68..d3f5153d549 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -958,10 +958,17 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo) if(nz->is_waiting) { if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n")) return 0; - } else if(nz->notify_send_enable) { - if(!ssl_printf(ssl, " notify: \"sent try %d " - "to %s with serial %u\"\n", nz->notify_retry, - nz->notify_current->ip_address_spec, + } else if(nz->notify_send_enable || nz->notify_send6_enable) { + int i; + if(!ssl_printf(ssl, " notify: \"send")) + return 0; + for(i=0; ipkts[i].dest) continue; + if(!ssl_printf(ssl, " %s", + nz->pkts[i].dest->ip_address_spec)) + return 0; + } + if(!ssl_printf(ssl, " with serial %u\"\n", (unsigned)ntohl(nz->current_soa->serial))) return 0; } @@ -985,6 +992,10 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo) if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified, xz->soa_notified_acquired)) return 0; + } else if(xz->event_added) { + if(!ssl_printf(ssl, "\twait: \"%u sec between attempts\"\n", + (unsigned)xz->timeout.tv_sec)) + return 0; } /* UDP */ diff --git a/usr.sbin/nsd/rrl.c b/usr.sbin/nsd/rrl.c index 2a7ca4f05b7..c8dec3fc908 100644 --- a/usr.sbin/nsd/rrl.c +++ b/usr.sbin/nsd/rrl.c @@ -156,7 +156,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2) if(!inet_ntop(AF_INET6, &a6, buf, sizeof(buf))) strlcpy(buf, "[ip6 ntop failed]", sizeof(buf)); else { - static char prefix[4]; + static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv6_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } @@ -170,7 +170,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2) if(!inet_ntop(AF_INET, &a4, buf, sizeof(buf))) strlcpy(buf, "[ip4 ntop failed]", sizeof(buf)); else { - static char prefix[4]; + static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv4_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } diff --git a/usr.sbin/nsd/util.h b/usr.sbin/nsd/util.h index b59b7b69bd1..5f00911d0a1 100644 --- a/usr.sbin/nsd/util.h +++ b/usr.sbin/nsd/util.h @@ -25,6 +25,10 @@ struct region; # define LOG_WARNING 4 # define LOG_NOTICE 5 # define LOG_INFO 6 + +/* Unused, but passed to log_open. */ +# define LOG_PID 0x01 +# define LOG_DAEMON (3<<3) #endif #define ALIGN_UP(n, alignment) \ diff --git a/usr.sbin/nsd/xfr-inspect.c b/usr.sbin/nsd/xfr-inspect.c new file mode 100644 index 00000000000..e31d64a413a --- /dev/null +++ b/usr.sbin/nsd/xfr-inspect.c @@ -0,0 +1,531 @@ +/* xfr-inspect - list the contents and inspect an zone transfer XFR file + * By W.C.A. Wijngaards + * Copyright 2017, NLnet Labs. + * BSD, see LICENSE. + */ + +#include "config.h" +#include "udbzone.h" +#include "util.h" +#include "buffer.h" +#include "packet.h" +#include "rdata.h" +#include "namedb.h" +#include "difffile.h" +#include +#include +#include +#include +#include +#include + +/** verbosity for inspect */ +static int v = 0; +/** shorthand for ease */ +#ifdef ULL +#undef ULL +#endif +#define ULL (unsigned long long) + +/** print usage text */ +static void +usage(void) +{ + printf("usage: xfr-inspect [options] file\n"); + printf(" -h this help\n"); + printf(" -v increase verbosity: " + "with -v(list chunks), -vv(inside chunks)\n"); + printf(" -l list contents of transfer\n"); +} + +static int +xi_diff_read_64(FILE *in, uint64_t* result) +{ + if (fread(result, sizeof(*result), 1, in) == 1) { + return 1; + } else { + return 0; + } +} + +static int +xi_diff_read_32(FILE *in, uint32_t* result) +{ + if (fread(result, sizeof(*result), 1, in) == 1) { + *result = ntohl(*result); + return 1; + } else { + return 0; + } +} + +static int +xi_diff_read_8(FILE *in, uint8_t* result) +{ + if (fread(result, sizeof(*result), 1, in) == 1) { + return 1; + } else { + return 0; + } +} + +static int +xi_diff_read_str(FILE* in, char* buf, size_t len) +{ + uint32_t disklen; + if(!xi_diff_read_32(in, &disklen)) + return 0; + if(disklen >= len) + return 0; + if(fread(buf, disklen, 1, in) != 1) + return 0; + buf[disklen] = 0; + return 1; +} + + +/** inspect header of xfr file, return num_parts */ +static int +inspect_header(FILE* in) +{ + char zone_buf[3072]; + char patname_buf[2048]; + + uint32_t old_serial, new_serial, num_parts, type; + uint64_t time_end_0, time_start_0; + uint32_t time_end_1, time_start_1; + uint8_t committed; + + time_t time_end, time_start; + + if(!xi_diff_read_32(in, &type)) { + printf("could not read type, file short\n"); + fclose(in); + exit(1); + } + if(type != DIFF_PART_XFRF) { + printf("type: %x (BAD FILE TYPE)\n", type); + fclose(in); + exit(1); + } + if(!xi_diff_read_8(in, &committed) || + !xi_diff_read_32(in, &num_parts) || + !xi_diff_read_64(in, &time_end_0) || + !xi_diff_read_32(in, &time_end_1) || + !xi_diff_read_32(in, &old_serial) || + !xi_diff_read_32(in, &new_serial) || + !xi_diff_read_64(in, &time_start_0) || + !xi_diff_read_32(in, &time_start_1) || + !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) || + !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) { + printf("diff file bad commit part, file too short"); + fclose(in); + exit(1); + } + time_end = (time_t)time_end_0; + time_start = (time_t)time_start_0; + + /* printf("type: %x\n", (int)type); */ + printf("committed: %d (%s)\n", (int)committed, + committed?"yes":"no"); + printf("num_parts: %d\n", (int)num_parts); + printf("time_end: %d.%6.6d %s", (int)time_end_0, + (int)time_end_1, ctime(&time_end)); + printf("old_serial: %u\n", (unsigned)old_serial); + printf("new_serial: %u\n", (unsigned)new_serial); + printf("time_start: %d.%6.6d %s", (int)time_start_0, + (int)time_start_1, ctime(&time_start)); + printf("zone: %s\n", zone_buf); + printf("patname: %s\n", patname_buf); + + return num_parts; +} + +/** print records in packet */ +static void +print_records(region_type* region, buffer_type* pkt, int num, int qsection) +{ + domain_table_type* table; + int i; + rr_type* rr; + region_type* tmpregion = region_create(xalloc, free); + buffer_type* tmpbuf; + if(!tmpregion) { + printf("out of memory\n"); + return; + } + tmpbuf = buffer_create(region, QIOBUFSZ); + if(!tmpbuf) { + printf("out of memory\n"); + return; + } + table = domain_table_create(tmpregion); + if(!table) { + printf("out of memory\n"); + return; + } + + for(i=0; iowner), + NULL)); + printf("\t%s", rrclass_to_string(rr->klass)); + if(rr->type == TYPE_IXFR) + printf("\tIXFR\n"); + else if(rr->type == TYPE_AXFR) + printf("\tAXFR\n"); + else printf("\t%s\n", rrtype_to_string(rr->type)); + } else { + if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) { + printf("; cannot print rr %d\n", i); + } + } + } + region_destroy(tmpregion); +} + +/** inspect packet (IXFR or AXFR) */ +static void +inspect_packet(region_type* region, buffer_type* pkt) +{ + printf("\n"); + if(buffer_limit(pkt) < QHEADERSZ) { + printf("packet too short\n"); + return; + } + printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n", + ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"", + RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"", + AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)), + OPCODE(pkt)); + printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n", + QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt)); + buffer_skip(pkt, QHEADERSZ); + + if(QDCOUNT(pkt) != 0) { + printf("; QUESTION SECTION\n"); + print_records(region, pkt, QDCOUNT(pkt), 1); + } + if(ANCOUNT(pkt) != 0) { + printf("; ANSWER SECTION\n"); + print_records(region, pkt, ANCOUNT(pkt), 0); + } + if(NSCOUNT(pkt) != 0) { + printf("; AUTHORITY SECTION\n"); + print_records(region, pkt, NSCOUNT(pkt), 0); + } + if(ARCOUNT(pkt) != 0) { + printf("; ADDITIONAL SECTION\n"); + print_records(region, pkt, ARCOUNT(pkt), 0); + } +} + +/** inspect part of xfr file */ +static void +inspect_part(FILE* in, int partnum) +{ + uint32_t pkttype, msglen, msglen2; + region_type* region; + buffer_type* packet; + region = region_create(xalloc, free); + if(!region) { + printf("out of memory\n"); + fclose(in); + exit(1); + } + packet = buffer_create(region, QIOBUFSZ); + if(!xi_diff_read_32(in, &pkttype)) { + printf("cannot read part %d\n", partnum); + fclose(in); + exit(1); + } + if(pkttype != DIFF_PART_XXFR) { + printf("bad part %d: not type XXFR\n", partnum); + fclose(in); + exit(1); + } + if(!xi_diff_read_32(in, &msglen)) { + printf("bad part %d: not msglen, file too short\n", partnum); + fclose(in); + exit(1); + } + if(msglen < QHEADERSZ || msglen > QIOBUFSZ) { + printf("bad part %d: msglen %u (too short or too long)\n", + partnum, (unsigned)msglen); + fclose(in); + exit(1); + } + if(fread(buffer_begin(packet), msglen, 1, in) != 1) { + printf("bad part %d: short packet, file too short, %s\n", + partnum, strerror(errno)); + fclose(in); + exit(1); + } + if(!xi_diff_read_32(in, &msglen2)) { + printf("bad part %d: cannot read msglen2, file too short\n", partnum); + fclose(in); + exit(1); + } + if(v==0) { + region_destroy(region); + return; + } + + printf("\n"); + /* printf("type : %x\n", pkttype); */ + printf("part : %d\n", partnum); + printf("msglen : %u\n", (unsigned)msglen); + printf("msglen2 : %u (%s)\n", (unsigned)msglen2, + (msglen==msglen2)?"ok":"wrong"); + + if(v>=2) { + buffer_set_limit(packet, msglen); + inspect_packet(region, packet); + } + + region_destroy(region); +} + +/** inspect parts of xfr file */ +static void +inspect_parts(FILE* in, int num) +{ + int i; + for(i=0; i QIOBUFSZ) { + printf("bad part %d: msglen %u (too short or too long)\n", + partnum, (unsigned)msglen); + fclose(in); + exit(1); + } + if(fread(buffer_begin(packet), msglen, 1, in) != 1) { + printf("bad part %d: short packet, file too short, %s\n", + partnum, strerror(errno)); + fclose(in); + exit(1); + } + if(!xi_diff_read_32(in, &msglen2)) { + printf("bad part %d: cannot read msglen2, file too short\n", partnum); + fclose(in); + exit(1); + } + + buffer_set_limit(packet, msglen); + list_packet(region, packet, partnum); + region_destroy(region); +} + +/** list parts of xfr file */ +static void +list_parts(FILE* in, int num) +{ + int i; + for(i=0; inotify_send_handler); if(zone->notify_send_handler.ev_fd != -1) { close(zone->notify_send_handler.ev_fd); + zone->notify_send_handler.ev_fd = -1; + } +} + +static void +notify_send6_disable(struct notify_zone* zone) +{ + zone->notify_send6_enable = 0; + event_del(&zone->notify_send6_handler); + if(zone->notify_send6_handler.ev_fd != -1) { + close(zone->notify_send6_handler.ev_fd); + zone->notify_send6_handler.ev_fd = -1; } } @@ -53,6 +60,9 @@ notify_disable(struct notify_zone* zone) if(zone->notify_send_enable) { notify_send_disable(zone); } + if(zone->notify_send6_enable) { + notify_send6_disable(zone); + } if(xfrd->notify_udp_num == XFRD_MAX_UDP_NOTIFY) { /* find next waiting and needy zone */ @@ -96,9 +106,12 @@ init_notify_send(rbtree_type* tree, region_type* region, sizeof(struct xfrd_soa)); memset(not->current_soa, 0, sizeof(struct xfrd_soa)); + not->notify_send_handler.ev_fd = -1; + not->notify_send6_handler.ev_fd = -1; not->is_waiting = 0; not->notify_send_enable = 0; + not->notify_send6_enable = 0; tsig_create_record_custom(¬->notify_tsig, NULL, 0, 0, 4); not->notify_current = 0; rbtree_insert(tree, (rbnode_type*)not); @@ -125,7 +138,7 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname) } /* event */ - if(not->notify_send_enable) { + if(not->notify_send_enable || not->notify_send6_enable) { notify_disable(not); } @@ -139,62 +152,134 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname) } static int -xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet) +reply_pkt_is_ack(struct notify_zone* zone, buffer_type* packet, int index) { if((OPCODE(packet) != OPCODE_NOTIFY) || (QR(packet) == 0)) { - log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags", - zone->apex_str); + log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags from %s", + zone->apex_str, zone->pkts[index].dest->ip_address_spec); + return 0; } /* we know it is OPCODE NOTIFY, QUERY_REPLY and for this zone */ - if(ID(packet) != zone->notify_query_id) { - log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID", - zone->apex_str); + if(ID(packet) != zone->pkts[index].notify_query_id) { + log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID from %s", + zone->apex_str, zone->pkts[index].dest->ip_address_spec); return 0; } /* could check tsig, but why. The reply does not cause processing. */ if(RCODE(packet) != RCODE_OK) { log_msg(LOG_ERR, "xfrd: zone %s: received notify response error %s from %s", zone->apex_str, rcode2str(RCODE(packet)), - zone->notify_current->ip_address_spec); + zone->pkts[index].dest->ip_address_spec); if(RCODE(packet) == RCODE_IMPL) return 1; /* rfc1996: notimpl notify reply: consider retries done */ return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: host %s acknowledges notify", - zone->apex_str, zone->notify_current->ip_address_spec)); + zone->apex_str, zone->pkts[index].dest->ip_address_spec)); return 1; } +/* compare sockaddr and acl_option addr and port numbers */ +static int +cmp_addr_equal(struct sockaddr* a, socklen_t a_len, struct acl_options* dest) +{ + if(dest) { + unsigned int destport = ((dest->port == 0)? + (unsigned)atoi(TCP_PORT):dest->port); +#ifdef INET6 + struct sockaddr_storage* a1 = (struct sockaddr_storage*)a; + if(a1->ss_family == AF_INET6 && dest->is_ipv6) { + struct sockaddr_in6* a2 = (struct sockaddr_in6*)a; + if(a_len < sizeof(struct sockaddr_in6)) + return 0; /* too small */ + if(ntohs(a2->sin6_port) != destport) + return 0; /* different port number */ + if(memcmp(&a2->sin6_addr, &dest->addr.addr6, + sizeof(struct in6_addr)) != 0) + return 0; /* different address */ + return 1; + } + if(a1->ss_family == AF_INET6 || dest->is_ipv6) + return 0; /* different address family */ + else { +#endif /* INET6 */ + struct sockaddr_in* a3 = (struct sockaddr_in*)a; + if(a_len < sizeof(struct sockaddr_in)) + return 0; /* too small */ + if(ntohs(a3->sin_port) != destport) + return 0; /* different port number */ + if(memcmp(&a3->sin_addr, &dest->addr.addr, + sizeof(struct in_addr)) != 0) + return 0; /* different address */ + return 1; +#ifdef INET6 + } +#endif + } + return 0; +} + static void -xfrd_notify_next(struct notify_zone* zone) +notify_pkt_done(struct notify_zone* zone, int index) { - /* advance to next in acl */ - zone->notify_current = zone->notify_current->next; - zone->notify_retry = 0; - if(zone->notify_current == 0) { - DEBUG(DEBUG_XFRD,1, (LOG_INFO, - "xfrd: zone %s: no more notify-send acls. stop notify.", - zone->apex_str)); - notify_disable(zone); + zone->pkts[index].dest = NULL; + zone->pkts[index].notify_retry = 0; + zone->pkts[index].send_time = 0; + zone->pkts[index].notify_query_id = 0; + zone->notify_pkt_count--; +} + +static void +notify_pkt_retry(struct notify_zone* zone, int index) +{ + if(++zone->pkts[index].notify_retry >= + zone->options->pattern->notify_retry) { + log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable", + zone->apex_str, + zone->pkts[index].dest->ip_address_spec); + notify_pkt_done(zone, index); return; } + if(!xfrd_notify_send_udp(zone, index)) { + notify_pkt_retry(zone, index); + } } static void -xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet) +xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet, + struct sockaddr* src, socklen_t srclen) { - int fd; - if(zone->notify_send_enable) { - notify_send_disable(zone); + int i; + for(i=0; ipkts[i].dest) + continue; + /* based on destination */ + if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest)) + continue; + if(reply_pkt_is_ack(zone, packet, i)) { + /* is done */ + notify_pkt_done(zone, i); + return; + } else { + /* retry */ + notify_pkt_retry(zone, i); + return; + } } - /* Set timeout for next reply */ - zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; +} + +static int +xfrd_notify_send_udp(struct notify_zone* zone, int index) +{ + buffer_type* packet = xfrd_get_temp_buffer(); + if(!zone->pkts[index].dest) return 0; /* send NOTIFY to secondary. */ xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex, qid_generate()); - zone->notify_query_id = ID(packet); + zone->pkts[index].notify_query_id = ID(packet); OPCODE_SET(packet, OPCODE_NOTIFY); AA_SET(packet); if(zone->current_soa->serial != 0) { @@ -202,35 +287,123 @@ xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet) ANCOUNT_SET(packet, 1); xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa); } - if(zone->notify_current->key_options) { - xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->notify_current); + if(zone->pkts[index].dest->key_options) { + xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest); } buffer_flip(packet); - fd = xfrd_send_udp(zone->notify_current, packet, - zone->options->pattern->outgoing_interface); - if(fd == -1) { - log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s", - zone->apex_str, zone->notify_retry, - zone->notify_current->ip_address_spec); - event_set(&zone->notify_send_handler, -1, EV_TIMEOUT, + + if((zone->pkts[index].dest->is_ipv6 + && zone->notify_send6_handler.ev_fd == -1) || + (!zone->pkts[index].dest->is_ipv6 + && zone->notify_send_handler.ev_fd == -1)) { + /* open fd */ + int fd = xfrd_send_udp(zone->pkts[index].dest, packet, + zone->options->pattern->outgoing_interface); + if(fd == -1) { + log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s", + zone->apex_str, zone->pkts[index].notify_retry, + zone->pkts[index].dest->ip_address_spec); + return 0; + } + if(zone->pkts[index].dest->is_ipv6) + zone->notify_send6_handler.ev_fd = fd; + else zone->notify_send_handler.ev_fd = fd; + } else { + /* send on existing fd */ +#ifdef INET6 + struct sockaddr_storage to; +#else + struct sockaddr_in to; +#endif /* INET6 */ + int fd; + socklen_t to_len = xfrd_acl_sockaddr_to( + zone->pkts[index].dest, &to); + if(zone->pkts[index].dest->is_ipv6) + fd = zone->notify_send6_handler.ev_fd; + else fd = zone->notify_send_handler.ev_fd; + if(sendto(fd, + buffer_current(packet), buffer_remaining(packet), 0, + (struct sockaddr*)&to, to_len) == -1) { + log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s", + zone->pkts[index].dest->ip_address_spec, + strerror(errno)); + return 0; + } + } + zone->pkts[index].send_time = time(NULL); + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s", + zone->apex_str, zone->pkts[index].notify_retry, + zone->pkts[index].dest->ip_address_spec)); + return 1; +} + +static void +notify_timeout_check(struct notify_zone* zone) +{ + time_t now = time(NULL); + int i; + for(i=0; ipkts[i].dest) + continue; + if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) { + notify_pkt_retry(zone, i); + } + } +} + +static void +notify_start_pkts(struct notify_zone* zone) +{ + int i; + if(!zone->notify_current) return; /* no more acl to send to */ + for(i=0; ipkts[i].dest==NULL && zone->notify_current) { + zone->pkts[i].dest = zone->notify_current; + zone->notify_current = zone->notify_current->next; + zone->pkts[i].notify_retry = 0; + zone->pkts[i].notify_query_id = 0; + zone->pkts[i].send_time = 0; + zone->notify_pkt_count++; + if(!xfrd_notify_send_udp(zone, i)) { + notify_pkt_retry(zone, i); + } + } + } +} + +static void +notify_setup_event(struct notify_zone* zone) +{ + if(zone->notify_send_handler.ev_fd != -1) { + int fd = zone->notify_send_handler.ev_fd; + if(zone->notify_send_enable) { + event_del(&zone->notify_send_handler); + } + zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; + event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); - if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) - log_msg(LOG_ERR, "notify_send: evtimer_add failed"); + if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) + log_msg(LOG_ERR, "notify_send: event_add failed"); zone->notify_send_enable = 1; - return; } - event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT, - xfrd_handle_notify_send, zone); - if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) - log_msg(LOG_ERR, "notify_send: event_base_set failed"); - if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) - log_msg(LOG_ERR, "notify_send: evtimer_add failed"); - zone->notify_send_enable = 1; - DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s", - zone->apex_str, zone->notify_retry, - zone->notify_current->ip_address_spec)); + if(zone->notify_send6_handler.ev_fd != -1) { + int fd = zone->notify_send6_handler.ev_fd; + if(zone->notify_send6_enable) { + event_del(&zone->notify_send6_handler); + } + zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; + event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT, + xfrd_handle_notify_send, zone); + if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0) + log_msg(LOG_ERR, "notify_send: event_base_set failed"); + if(event_add(&zone->notify_send6_handler, &zone->notify_timeout) != 0) + log_msg(LOG_ERR, "notify_send: event_add failed"); + zone->notify_send6_enable = 1; + } } static void @@ -238,44 +411,54 @@ xfrd_handle_notify_send(int fd, short event, void* arg) { struct notify_zone* zone = (struct notify_zone*)arg; buffer_type* packet = xfrd_get_temp_buffer(); - assert(zone->notify_current); if(zone->is_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: notify waiting, skipped, %s", zone->apex_str)); return; } if((event & EV_READ)) { + struct sockaddr_storage src; + socklen_t srclen = (socklen_t)sizeof(src); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: read notify ACK", zone->apex_str)); assert(fd != -1); - if(xfrd_udp_read_packet(packet, fd)) { - if(xfrd_handle_notify_reply(zone, packet)) - xfrd_notify_next(zone); + if(xfrd_udp_read_packet(packet, fd, (struct sockaddr*)&src, + &srclen)) { + /* find entry, send retry or make entry NULL */ + xfrd_handle_notify_reply(zone, packet, + (struct sockaddr*)&src, srclen); } - } else if((event & EV_TIMEOUT)) { + } + if((event & EV_TIMEOUT)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout", zone->apex_str)); /* timeout, try again */ } - /* see if notify is still enabled */ - if(zone->notify_current) { - zone->notify_retry++; - if(zone->notify_retry > zone->options->pattern->notify_retry) { - log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable", - zone->apex_str, zone->notify_current->ip_address_spec); - xfrd_notify_next(zone); - } - } - if(zone->notify_current) { - /* try again */ - xfrd_notify_send_udp(zone, packet); + + /* see which pkts have timeouted, retry or NULL them */ + notify_timeout_check(zone); + + /* start new packets if we have empty space */ + notify_start_pkts(zone); + + /* see if we are done */ + if(!zone->notify_current && !zone->notify_pkt_count) { + /* we are done */ + DEBUG(DEBUG_XFRD,1, (LOG_INFO, + "xfrd: zone %s: no more notify-send acls. stop notify.", + zone->apex_str)); + notify_disable(zone); + return; } + + notify_setup_event(zone); } static void setup_notify_active(struct notify_zone* zone) { - zone->notify_retry = 0; + zone->notify_pkt_count = 0; + memset(zone->pkts, 0, sizeof(zone->pkts)); zone->notify_current = zone->options->pattern->notify; zone->notify_timeout.tv_sec = 0; zone->notify_timeout.tv_usec = 0; @@ -329,7 +512,8 @@ void xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd) { xfrd_zone_type* xz; - if(zone->is_waiting || zone->notify_send_enable) + if(zone->is_waiting || zone->notify_send_enable || + zone->notify_send6_enable) return; xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, zone->apex); if(xz && xz->soa_nsd_acquired) @@ -344,7 +528,7 @@ xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new struct notify_zone* zone = (struct notify_zone*) rbtree_search(tree, apex); assert(zone); - if(zone->notify_send_enable) + if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); @@ -363,7 +547,7 @@ notify_handle_master_zone_soainfo(rbtree_type* tree, if( (new_soa == NULL && zone->current_soa->serial == 0) || (new_soa && new_soa->serial == zone->current_soa->serial)) return; - if(zone->notify_send_enable) + if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); } @@ -374,7 +558,7 @@ close_notify_fds(rbtree_type* tree) struct notify_zone* zone; RBTREE_FOR(zone, struct notify_zone*, tree) { - if(zone->notify_send_enable) + if(zone->notify_send_enable || zone->notify_send6_enable) notify_send_disable(zone); } } diff --git a/usr.sbin/nsd/xfrd-notify.h b/usr.sbin/nsd/xfrd-notify.h index 153dca5129b..3a20f383ff1 100644 --- a/usr.sbin/nsd/xfrd-notify.h +++ b/usr.sbin/nsd/xfrd-notify.h @@ -33,6 +33,17 @@ struct xfrd_soa; struct acl_options; struct xfrd_state; +/** number of concurrent notify packets in flight */ +#define NOTIFY_CONCURRENT_MAX 16 + +/** notify packet info */ +struct notify_pkt { + struct acl_options* dest; /* target, NULL if entry not in use */ + uint8_t notify_retry; /* how manieth retry in sending to current */ + uint16_t notify_query_id; + time_t send_time; +}; + /** * This struct keeps track of outbound notifies for a zone. */ @@ -50,18 +61,20 @@ struct notify_zone { /* Not saved on disk (i.e. kill of daemon stops notifies) */ int notify_send_enable; struct event notify_send_handler; + int notify_send6_enable; + struct event notify_send6_handler; struct timeval notify_timeout; struct acl_options* notify_current; /* current slave to notify */ uint8_t notify_restart; /* restart notify after repattern */ - uint8_t notify_retry; /* how manieth retry in sending to current */ - uint16_t notify_query_id; + struct notify_pkt pkts[NOTIFY_CONCURRENT_MAX]; + int notify_pkt_count; /* number of entries nonNULL in pkts */ /* is this notify waiting for a socket? */ uint8_t is_waiting; /* the double linked waiting list for the udp sockets */ struct notify_zone* waiting_next; struct notify_zone* waiting_prev; -}; +} ATTR_PACKED; /* initialise outgoing notifies */ void init_notify_send(rbtree_type* tree, region_type* region, diff --git a/usr.sbin/nsd/xfrd-tcp.c b/usr.sbin/nsd/xfrd-tcp.c index 2715689439f..3c176a38ff8 100644 --- a/usr.sbin/nsd/xfrd-tcp.c +++ b/usr.sbin/nsd/xfrd-tcp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "nsd.h" #include "xfrd-tcp.h" #include "buffer.h" @@ -898,6 +899,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp) tp->id[zone->query_id] = TCP_NULL_SKIP; tp->num_skip++; /* fall through to remove zone from tp */ + /* fallthrough */ case xfrd_packet_transfer: if(zone->zone_options->pattern->multi_master_check) { xfrd_tcp_release(xfrd->tcp_set, zone); diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index 1c03750dacf..3520f5d3b1b 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/xfrd.c @@ -767,7 +767,7 @@ xfrd_set_timer_retry(xfrd_zone_type* zone) else if(set_retry < (time_t)zone->zone_options->pattern->min_retry_time) set_retry = zone->zone_options->pattern->min_retry_time; if(set_retry < XFRD_LOWERBOUND_RETRY) - set_retry = XFRD_LOWERBOUND_RETRY; + set_retry = XFRD_LOWERBOUND_RETRY; xfrd_set_timer(zone, set_retry); } else { set_retry = ntohl(zone->soa_disk.expire); @@ -1210,14 +1210,15 @@ xfrd_send_expire_notification(xfrd_zone_type* zone) } int -xfrd_udp_read_packet(buffer_type* packet, int fd) +xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src, + socklen_t* srclen) { ssize_t received; /* read the data */ buffer_clear(packet); received = recvfrom(fd, buffer_begin(packet), buffer_remaining(packet), - 0, NULL, NULL); + 0, src, srclen); if(received == -1) { log_msg(LOG_ERR, "xfrd: recvfrom failed: %s", strerror(errno)); @@ -1299,7 +1300,8 @@ static void xfrd_udp_read(xfrd_zone_type* zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s read udp data", zone->apex_str)); - if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd)) { + if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd, + NULL, NULL)) { zone->master->bad_xfr_count++; if (zone->master->bad_xfr_count > 2) { xfrd_disable_ixfr(zone); @@ -1323,6 +1325,7 @@ xfrd_udp_read(xfrd_zone_type* zone) xfrd_make_request(zone); break; } + /* fallthrough */ case xfrd_packet_newlease: /* nothing more to do */ assert(zone->round_num == -1); diff --git a/usr.sbin/nsd/xfrd.h b/usr.sbin/nsd/xfrd.h index 44e7ba1795a..c58780c7065 100644 --- a/usr.sbin/nsd/xfrd.h +++ b/usr.sbin/nsd/xfrd.h @@ -136,7 +136,7 @@ struct xfrd_soa { uint32_t retry; uint32_t expire; uint32_t minimum; -}; +} ATTR_PACKED; /* @@ -219,7 +219,7 @@ struct xfrd_zone { valid if msg_seq_nr nonzero */ int multi_master_first_master; /* >0: first check master_num */ int multi_master_update_check; /* -1: not update >0: last update master_num */ -}; +} ATTR_PACKED; enum xfrd_packet_result { xfrd_packet_bad, /* drop the packet/connection */ @@ -239,10 +239,10 @@ enum xfrd_packet_result { Note that also some sockets are used for writing the ixfr.db, xfrd.state files and for the pipes to the main parent process. */ -#define XFRD_MAX_TCP 32 /* max number of TCP AXFR/IXFR concurrent connections.*/ +#define XFRD_MAX_TCP 128 /* max number of TCP AXFR/IXFR concurrent connections.*/ /* Each entry has 64Kb buffer preallocated.*/ -#define XFRD_MAX_UDP 64 /* max number of UDP sockets at a time for IXFR */ -#define XFRD_MAX_UDP_NOTIFY 64 /* max concurrent UDP sockets for NOTIFY */ +#define XFRD_MAX_UDP 128 /* max number of UDP sockets at a time for IXFR */ +#define XFRD_MAX_UDP_NOTIFY 128 /* max concurrent UDP sockets for NOTIFY */ #define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 2*x seconds */ #define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */ @@ -300,7 +300,8 @@ int xfrd_send_udp(struct acl_options* acl, buffer_type* packet, /* * read from udp port packet into buffer, returns 0 on failure */ -int xfrd_udp_read_packet(buffer_type* packet, int fd); +int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src, + socklen_t* srclen); /* * Release udp socket that a zone is using diff --git a/usr.sbin/nsd/zlexer.lex b/usr.sbin/nsd/zlexer.lex index 90a1df3741c..728f92603f6 100644 --- a/usr.sbin/nsd/zlexer.lex +++ b/usr.sbin/nsd/zlexer.lex @@ -83,6 +83,16 @@ parser_pop_stringbuf(void) oldstate = NULL; } + static int paren_open = 0; + static enum lexer_state lexer_state = EXPECT_OWNER; +void +parser_flush(void) +{ + YY_FLUSH_BUFFER; + paren_open = 0; + lexer_state = EXPECT_OWNER; +} + #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ @@ -119,8 +129,6 @@ ANY [^\"\n\\]|\\. %x incl bitlabel quotedstring %% - static int paren_open = 0; - static enum lexer_state lexer_state = EXPECT_OWNER; {SPACE}*{COMMENT}.* /* ignore */ ^{DOLLAR}TTL { lexer_state = PARSING_RDATA; return DOLLAR_TTL; } ^{DOLLAR}ORIGIN { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; } diff --git a/usr.sbin/nsd/zonec.c b/usr.sbin/nsd/zonec.c index 1b20b84d90f..de0a03ca4cd 100644 --- a/usr.sbin/nsd/zonec.c +++ b/usr.sbin/nsd/zonec.c @@ -1627,6 +1627,7 @@ zonec_read(const char* name, const char* zonefile, zone_type* zone) parser->current_zone->soa_rrset->rrs[0].owner)); } + parser_flush(); fclose(yyin); if(!zone_is_slave(zone->opts)) check_dname(zone); @@ -1719,5 +1720,6 @@ zonec_parse_string(region_type* region, domain_table_type* domains, if(parser->origin != error_domain) domain_table_deldomain(parser->db, parser->origin); zonec_desetup_string_parser(); + parser_flush(); return errors; } diff --git a/usr.sbin/nsd/zonec.h b/usr.sbin/nsd/zonec.h index 4057b12cf36..b14bedb20ca 100644 --- a/usr.sbin/nsd/zonec.h +++ b/usr.sbin/nsd/zonec.h @@ -82,6 +82,7 @@ void zc_error_prev_line(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2); void parser_push_stringbuf(char* str); void parser_pop_stringbuf(void); +void parser_flush(void); int process_rr(void); uint16_t *zparser_conv_hex(region_type *region, const char *hex, size_t len);