Update nsd to 4.1.19.
authorflorian <florian@openbsd.org>
Sat, 3 Feb 2018 11:03:51 +0000 (11:03 +0000)
committerflorian <florian@openbsd.org>
Sat, 3 Feb 2018 11:03:51 +0000 (11:03 +0000)
OK sthen@, "so far so good" millert@

Obligatory commit from 33,000 ft.

26 files changed:
usr.sbin/nsd/Makefile.in
usr.sbin/nsd/axfr.c
usr.sbin/nsd/difffile.c
usr.sbin/nsd/lookup3.c
usr.sbin/nsd/namedb.c
usr.sbin/nsd/namedb.h
usr.sbin/nsd/netio.c
usr.sbin/nsd/nsd.c
usr.sbin/nsd/nsec3.c
usr.sbin/nsd/options.h
usr.sbin/nsd/query.c
usr.sbin/nsd/radtree.h
usr.sbin/nsd/rbtree.h
usr.sbin/nsd/region-allocator.c
usr.sbin/nsd/remote.c
usr.sbin/nsd/rrl.c
usr.sbin/nsd/util.h
usr.sbin/nsd/xfr-inspect.c [new file with mode: 0644]
usr.sbin/nsd/xfrd-notify.c
usr.sbin/nsd/xfrd-notify.h
usr.sbin/nsd/xfrd-tcp.c
usr.sbin/nsd/xfrd.c
usr.sbin/nsd/xfrd.h
usr.sbin/nsd/zlexer.lex
usr.sbin/nsd/zonec.c
usr.sbin/nsd/zonec.h

index 495160c..3468101 100644 (file)
@@ -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
index 6f6b095..dd34c0c 100644 (file)
@@ -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;
index dfef60d..1fb5bda 100644 (file)
@@ -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);
        }
index e0179f0..9602ffa 100644 (file)
@@ -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;
index bcc41aa..bc7690d 100644 (file)
@@ -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));
        }
index e2d8451..c7cf6d9 100644 (file)
@@ -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.
index 6c4b395..58fd2e1 100644 (file)
@@ -94,7 +94,7 @@ netio_current_time(netio_type *netio)
        if (!netio->have_current_time) {
                struct timeval current_timeval;
                if (gettimeofday(&current_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, &current_timeval);
index f2cf6cc..dfbc586 100644 (file)
@@ -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);
index 960e721..dad4f23 100644 (file)
@@ -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;
        }
index dedb9bf..bbfbbf9 100644 (file)
@@ -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 {
index d6e45a2..7b862a4 100644 (file)
@@ -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) */
index fdc58e7..c5d830a 100644 (file)
@@ -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
index d6e5486..eb9b394 100644 (file)
@@ -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 *));
index 95454a6..8b5d2c7 100644 (file)
 #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)<SIZEOF_VOIDP?SIZEOF_VOIDP:(x))
+#define ALIGNMENT 1
+#endif /* PACKED_STRUCTS */
 /* #define CHECK_DOUBLE_FREE 0 */ /* set to 1 to perform expensive check for double recycle() */
 
 typedef struct cleanup cleanup_type;
@@ -285,7 +290,13 @@ region_alloc(region_type *region, size_t size)
                        return NULL;
 
                wasted = (region->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;
index f7c8822..d3f5153 100644 (file)
@@ -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; i<NOTIFY_CONCURRENT_MAX; i++) {
+                               if(!nz->pkts[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 */
index 2a7ca4f..c8dec3f 100644 (file)
@@ -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));
        }
index b59b7b6..5f00911 100644 (file)
@@ -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 (file)
index 0000000..e31d64a
--- /dev/null
@@ -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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/** 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; i<num; ++i) {
+               rr = packet_read_rr(region, table, pkt, qsection);
+               if(!rr) {
+                       printf("; cannot read rr %d\n", i);
+                       return;
+               }
+               if(qsection) {
+                       printf("%s", dname_to_string(domain_dname(rr->owner),
+                               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<num; i++) {
+               inspect_part(in, i);
+       }
+}
+
+/** inspect trail of xfr file */
+static void
+inspect_trail(FILE* in)
+{
+       char log_buf[5120];
+       if(!xi_diff_read_str(in, log_buf, sizeof(log_buf))) {
+               printf("bad trail: cannot read log string\n");
+               fclose(in);
+               exit(1);
+       }
+       printf("\n");
+       printf("log:    %s\n", log_buf);
+}
+
+/** inspect contents of xfr file */
+static void
+inspect_file(char* fname)
+{
+       FILE* in;
+       int num;
+       log_init("udb-inspect");
+       if(!(in=fopen(fname, "r"))) {
+               printf("cannot open %s: %s\n", fname, strerror(errno));
+               exit(1);
+       }
+       printf("file:   %s\n", fname);
+       num = inspect_header(in);
+       inspect_parts(in, num);
+       inspect_trail(in);
+       fclose(in);
+}
+
+/** list header of xfr file, return num_parts */
+static int
+list_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("; commited:     %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;
+}
+
+/** list packet (IXFR or AXFR) */
+static void
+list_packet(region_type* region, buffer_type* pkt, int partnum)
+{
+       if(buffer_limit(pkt) < QHEADERSZ) {
+               printf("packet too short\n");
+               return;
+       }
+       buffer_skip(pkt, QHEADERSZ);
+
+       if(partnum == 0 && QDCOUNT(pkt) == 1) {
+               /* print query AXFR or IXFR */
+               printf("; ");
+               print_records(region, pkt, QDCOUNT(pkt), 1);
+       }
+       if(ANCOUNT(pkt) != 0) {
+               print_records(region, pkt, ANCOUNT(pkt), 0);
+       }
+}
+
+/** list part of xfr file */
+static void
+list_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);
+       }
+
+       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; i<num; i++) {
+               list_part(in, i);
+       }
+}
+
+/** list contents of xfr file */
+static void
+list_file(char* fname)
+{
+       FILE* in;
+       int num;
+       log_init("udb-inspect");
+       if(!(in=fopen(fname, "r"))) {
+               printf("cannot open %s: %s\n", fname, strerror(errno));
+               exit(1);
+       }
+       num = list_header(in);
+       list_parts(in, num);
+
+       fclose(in);
+}
+
+/** getopt global, in case header files fail to declare it. */
+extern int optind;
+/** getopt global, in case header files fail to declare it. */
+extern char* optarg;
+
+/**
+ * main program. Set options given commandline arguments.
+ * @param argc: number of commandline arguments.
+ * @param argv: array of commandline arguments.
+ * @return: exit status of the program.
+ */
+int
+main(int argc, char* argv[])
+{
+       int c, list=0;
+       while( (c=getopt(argc, argv, "hlv")) != -1) {
+               switch(c) {
+               case 'l':
+                       list=1;
+                       break;
+               case 'v':
+                       v++;
+                       break;
+               default:
+               case 'h':
+                       usage();
+                       return 1;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if(argc != 1) {
+               usage();
+               return 1;
+       }
+       if(list) list_file(argv[0]);
+       else    inspect_file(argv[0]);
+
+       return 0;
+}
index 918b321..3f9853e 100644 (file)
@@ -17,7 +17,7 @@
 #include "xfrd-tcp.h"
 #include "packet.h"
 
-#define XFRD_NOTIFY_RETRY_TIMOUT 15 /* seconds between retries sending NOTIFY */
+#define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */
 
 /* start sending notifies */
 static void notify_enable(struct notify_zone* zone,
@@ -25,15 +25,10 @@ static void notify_enable(struct notify_zone* zone,
 /* setup the notify active state */
 static void setup_notify_active(struct notify_zone* zone);
 
-/* returns if the notify send is done for the notify_current acl */
-static int xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet);
-
 /* handle zone notify send */
 static void xfrd_handle_notify_send(int fd, short event, void* arg);
 
-static void xfrd_notify_next(struct notify_zone* zone);
-
-static void xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet);
+static int xfrd_notify_send_udp(struct notify_zone* zone, int index);
 
 static void
 notify_send_disable(struct notify_zone* zone)
@@ -42,6 +37,18 @@ notify_send_disable(struct notify_zone* zone)
        event_del(&zone->notify_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(&not->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; i<NOTIFY_CONCURRENT_MAX; i++) {
+               /* is this entry in use */
+               if(!zone->pkts[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; i<NOTIFY_CONCURRENT_MAX; i++) {
+               if(!zone->pkts[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; i<NOTIFY_CONCURRENT_MAX; i++) {
+               /* while loop, in case the retries all fail, and we can
+                * start another on this slot, or run out of notify acls */
+               while(zone->pkts[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);
        }
 }
index 153dca5..3a20f38 100644 (file)
@@ -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,
index 2715689..3c176a3 100644 (file)
@@ -13,6 +13,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <sys/uio.h>
 #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);
index 1c03750..3520f5d 100644 (file)
@@ -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);
index 44e7ba1..c58780c 100644 (file)
@@ -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
index 90a1df3..728f926 100644 (file)
@@ -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; }
index 1b20b84..de0a03c 100644 (file)
@@ -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;
 }
index 4057b12..b14bedb 100644 (file)
@@ -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);