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"' > $@ ;\
$(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
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;
/* 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;
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 */
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);
}
}
{
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);
}
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.
*/
/*
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 */
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;
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 */
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;
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));
}
};
#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;
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
#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. */
*/
unsigned is_existing : 1;
unsigned is_apex : 1;
-};
+} ATTR_PACKED;
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 {
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
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.
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);
case 'v':
version();
/* version exits */
+ break;
#ifndef NDEBUG
case 'F':
sscanf(optarg, "%x", &nsd_debug_facilities);
break;
case -1:
error("fork() failed: %s", strerror(errno));
+ break;
default:
/* Parent is done */
server_close_all_sockets(nsd.udp, nsd.ifs);
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 */
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 */
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
/** 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
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);
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;
}
/* 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
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
{
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)) {
{
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)) {
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;
}
uint8_t min_retry_time_is_default;
uint64_t size_limit_xfr;
uint8_t multi_master_check;
-};
+} ATTR_PACKED;
#define PATTERN_IMPLICIT_MARKER "_implicit_"
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
uint8_t blocked;
const char* key_name;
struct key_options* key_options;
-};
+} ATTR_PACKED;
/*
* Key definition
char* algorithm;
char* secret;
struct tsig_key* tsig_key;
-};
+} ATTR_PACKED;
/** zone list free space */
struct zonelist_free {
* 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) */
uint16_t capacity;
/** the lookup array by [byte-offset] */
struct radsel* array;
-};
+} ATTR_PACKED;
/**
* radix select edge in array
radstrlen_type len;
/** node that deals with byte+str */
struct radnode* node;
-};
+} ATTR_PACKED;
/**
* Create new radix tree
rbnode_type *right;
const void *key;
uint8_t color;
-};
+} ATTR_PACKED;
#define RBTREE_NULL &rbtree_null_node
extern rbnode_type rbtree_null_node;
/* 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 *));
#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;
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;
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;
}
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 */
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));
}
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));
}
# 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) \
--- /dev/null
+/* 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;
+}
#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,
/* 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)
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;
}
}
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 */
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);
}
/* event */
- if(not->notify_send_enable) {
+ if(not->notify_send_enable || not->notify_send6_enable) {
notify_disable(not);
}
}
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) {
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
{
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;
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)
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);
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);
}
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);
}
}
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.
*/
/* 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,
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
+#include <sys/uio.h>
#include "nsd.h"
#include "xfrd-tcp.h"
#include "buffer.h"
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);
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);
}
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));
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);
xfrd_make_request(zone);
break;
}
+ /* fallthrough */
case xfrd_packet_newlease:
/* nothing more to do */
assert(zone->round_num == -1);
uint32_t retry;
uint32_t expire;
uint32_t minimum;
-};
+} ATTR_PACKED;
/*
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 */
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 */
/*
* 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
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) \
{ \
%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; }
parser->current_zone->soa_rrset->rrs[0].owner));
}
+ parser_flush();
fclose(yyin);
if(!zone_is_slave(zone->opts))
check_dname(zone);
if(parser->origin != error_domain)
domain_table_deldomain(parser->db, parser->origin);
zonec_desetup_string_parser();
+ parser_flush();
return errors;
}
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);