nsd-4.1.26/0000775000175000017500000000000013401455025012025 5ustar wouterwouternsd-4.1.26/nsec3.h0000664000175000017500000001015713334272434013223 0ustar wouterwouter/* * nsec3.h -- nsec3 handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef NSEC3_H #define NSEC3_H #ifdef NSEC3 struct udb_ptr; struct domain; struct dname; struct region; struct zone; struct namedb; struct query; struct answer; struct rr; /* * calculate prehash information for zone. */ void prehash_zone(struct namedb* db, struct zone* zone); /* * calculate prehash for zone, assumes no partial precompile or prehashlist */ void prehash_zone_complete(struct namedb* db, struct zone* zone); /* * finds nsec3 that covers the given domain hash. * returns true if the find is exact. */ int nsec3_find_cover(struct zone* zone, uint8_t* hash, size_t hashlen, struct domain** result); /* * _answer_ Routines used to add the correct nsec3 record to a query answer. * cnames etc may have been followed, hence original name. */ /* * add proof for wildcards that the name below the wildcard.parent * does not exist */ void nsec3_answer_wildcard(struct query* query, struct answer* answer, struct domain* wildcard, const struct dname* qname); /* * add NSEC3 to provide domain name but not rrset exists, * this could be a query for a DS or NSEC3 type */ void nsec3_answer_nodata(struct query *query, struct answer *answer, struct domain *original); /* * add NSEC3 for a delegation (optout stuff) */ void nsec3_answer_delegation(struct query *query, struct answer *answer); /* * add NSEC3 for authoritative answers. * match==0 is an nxdomain. */ void nsec3_answer_authoritative(struct domain** match, struct query *query, struct answer *answer, struct domain* closest_encloser, const struct dname* qname); /* * True if domain is a NSEC3 (+RRSIG) data only variety. * pass nonNULL zone to filter for particular zone. */ int domain_has_only_NSEC3(struct domain* domain, struct zone* zone); /* get hashed bytes */ void nsec3_hash_and_store(struct zone* zone, const struct dname* dname, uint8_t* store); /* see if NSEC3 record uses the params in use for the zone */ int nsec3_rr_uses_params(struct rr* rr, struct zone* zone); /* number of NSEC3s that are in the zone chain */ int nsec3_in_chain_count(struct domain* domain, struct zone* zone); /* find previous NSEC3, or, lastinzone, or, NULL */ struct domain* nsec3_chain_find_prev(struct zone* zone, struct domain* domain); /* clear nsec3 precompile for the zone */ void nsec3_clear_precompile(struct namedb* db, struct zone* zone); /* if domain is part of nsec3hashed domains of a zone */ int nsec3_domain_part_of_zone(struct domain* d, struct zone* z); /* condition when a domain is precompiled */ int nsec3_condition_hash(struct domain* d, struct zone* z); /* condition when a domain is ds precompiled */ int nsec3_condition_dshash(struct domain* d, struct zone* z); /* set nsec3param for this zone or NULL if no NSEC3 available */ void nsec3_find_zone_param(struct namedb* db, struct zone* zone, struct udb_ptr* z, struct rr* avoid_rr, int checkchain); /* hash domain and wcchild, and lookup nsec3 in tree, and precompile */ void nsec3_precompile_domain(struct namedb* db, struct domain* domain, struct zone* zone, struct region* tmpregion); /* hash ds_parent_cover, and lookup nsec3 and precompile */ void nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, struct zone* zone); /* put nsec3 into nsec3tree and adjust zonelast */ void nsec3_precompile_nsec3rr(struct namedb* db, struct domain* domain, struct zone* zone); /* precompile entire zone, assumes all is null at start */ void nsec3_precompile_newparam(struct namedb* db, struct zone* zone); /* create b32.zone for a hash, allocated in the region */ const struct dname* nsec3_b32_create(struct region* region, struct zone* zone, unsigned char* hash); /* create trees for nsec3 updates and lookups in zone */ void nsec3_zone_trees_create(struct region* region, struct zone* zone); /* lookup zone that contains domain's nsec3 trees */ struct zone* nsec3_tree_zone(struct namedb* db, struct domain* domain); /* lookup zone that contains domain's ds tree */ struct zone* nsec3_tree_dszone(struct namedb* db, struct domain* domain); #endif /* NSEC3 */ #endif /* NSEC3_H*/ nsd-4.1.26/udbzone.c0000664000175000017500000005376712652624650013672 0ustar wouterwouter/* * udbzone -- store zone and rrset information in udb file. * * Copyright (c) 2011, NLnet Labs. See LICENSE for license. */ #include "config.h" #include "udbzone.h" #include "util.h" #include "iterated_hash.h" #include "dns.h" #include "dname.h" #include "difffile.h" #include /** delete the zone plain its own data */ static void udb_zone_delete_plain(udb_base* udb, udb_ptr* zone) { udb_ptr dtree; assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); udb_zone_clear(udb, zone); udb_rptr_zero(&ZONE(zone)->node, udb); udb_rptr_zero(&ZONE(zone)->nsec3param, udb); udb_rptr_zero(&ZONE(zone)->log_str, udb); udb_rptr_zero(&ZONE(zone)->file_str, udb); udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); udb_rptr_zero(&ZONE(zone)->domains, udb); udb_radix_tree_delete(udb, &dtree); udb_ptr_free_space(zone, udb, sizeof(struct zone_d)+ZONE(zone)->namelen); } int udb_dns_init_file(udb_base* udb) { udb_ptr ztree; if(!udb_radix_tree_create(udb, &ztree)) { return 0; } udb_base_set_userdata(udb, ztree.data); udb_ptr_unlink(&ztree, udb); return 1; } void udb_dns_deinit_file(udb_base* udb) { udb_ptr ztree; udb_ptr z; udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); if(udb_ptr_is_null(&ztree)) { return; } assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); /* delete all zones */ for(udb_radix_first(udb, &ztree, &z); z.data; udb_radix_next(udb, &z)){ udb_ptr zone; udb_ptr_new(&zone, udb, &RADNODE(&z)->elem); udb_rptr_zero(&RADNODE(&z)->elem, udb); udb_zone_delete_plain(udb, &zone); } udb_ptr_unlink(&z, udb); udb_base_set_userdata(udb, 0); udb_radix_tree_delete(udb, &ztree); } int udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname, size_t dlen) { udb_ptr ztree, z, node, dtree; udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); udb_ptr_init(result, udb); if(udb_zone_search(udb, &z, dname, dlen)) { udb_ptr_unlink(&ztree, udb); udb_ptr_unlink(&z, udb); /* duplicate */ return 0; } if(!udb_ptr_alloc_space(&z, udb, udb_chunk_type_zone, sizeof(struct zone_d)+dlen)) { udb_ptr_unlink(&ztree, udb); /* failed alloc */ return 0; } /* init the zone object */ udb_rel_ptr_init(&ZONE(&z)->node); udb_rel_ptr_init(&ZONE(&z)->domains); udb_rel_ptr_init(&ZONE(&z)->nsec3param); udb_rel_ptr_init(&ZONE(&z)->log_str); udb_rel_ptr_init(&ZONE(&z)->file_str); ZONE(&z)->rrset_count = 0; ZONE(&z)->rr_count = 0; ZONE(&z)->expired = 0; ZONE(&z)->mtime = 0; ZONE(&z)->mtime_nsec = 0; ZONE(&z)->namelen = dlen; memmove(ZONE(&z)->name, dname, dlen); if(!udb_radix_tree_create(udb, &dtree)) { udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); udb_ptr_unlink(&ztree, udb); /* failed alloc */ return 0; } udb_rptr_set_ptr(&ZONE(&z)->domains, udb, &dtree); /* insert it */ if(!udb_radname_insert(udb, &ztree, dname, dlen, &z, &node)) { udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); udb_ptr_unlink(&ztree, udb); udb_radix_tree_delete(udb, &dtree); udb_ptr_unlink(&dtree, udb); /* failed alloc */ return 0; } udb_rptr_set_ptr(&ZONE(&z)->node, udb, &node); udb_ptr_set_ptr(result, udb, &z); udb_ptr_unlink(&z, udb); udb_ptr_unlink(&dtree, udb); udb_ptr_unlink(&ztree, udb); udb_ptr_unlink(&node, udb); return 1; } /** delete an RR */ static void rr_delete(udb_base* udb, udb_ptr* rr) { assert(udb_ptr_get_type(rr) == udb_chunk_type_rr); udb_rptr_zero(&RR(rr)->next, udb); udb_ptr_free_space(rr, udb, sizeof(struct rr_d)+RR(rr)->len); } /** delete an rrset */ static void rrset_delete(udb_base* udb, udb_ptr* rrset) { udb_ptr rr, n; assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); /* free RRs */ udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); udb_ptr_init(&n, udb); udb_rptr_zero(&RRSET(rrset)->rrs, udb); while(!udb_ptr_is_null(&rr)) { udb_ptr_set_rptr(&n, udb, &RR(&rr)->next); rr_delete(udb, &rr); udb_ptr_set_ptr(&rr, udb, &n); udb_ptr_zero(&n, udb); } udb_ptr_unlink(&n, udb); udb_ptr_unlink(&rr, udb); udb_rptr_zero(&RRSET(rrset)->next, udb); udb_ptr_free_space(rrset, udb, sizeof(struct rrset_d)); } /** clear a domain of its rrsets, rrs */ static void domain_clear(udb_base* udb, udb_ptr* d) { udb_ptr rrset, n; assert(udb_ptr_get_type(d) == udb_chunk_type_domain); udb_ptr_new(&rrset, udb, &DOMAIN(d)->rrsets); udb_ptr_init(&n, udb); udb_rptr_zero(&DOMAIN(d)->rrsets, udb); while(!udb_ptr_is_null(&rrset)) { udb_ptr_set_rptr(&n, udb, &RRSET(&rrset)->next); rrset_delete(udb, &rrset); udb_ptr_set_ptr(&rrset, udb, &n); udb_ptr_zero(&n, udb); } udb_ptr_unlink(&n, udb); udb_ptr_unlink(&rrset, udb); } /** delete a domain and all its rrsets, rrs */ static void domain_delete(udb_base* udb, udb_ptr* d) { domain_clear(udb, d); udb_rptr_zero(&DOMAIN(d)->node, udb); udb_ptr_free_space(d, udb, sizeof(struct domain_d)+DOMAIN(d)->namelen); } /** delete domain but also unlink from tree at zone */ static void domain_delete_unlink(udb_base* udb, udb_ptr* z, udb_ptr* d) { udb_ptr dtree, n; udb_ptr_new(&dtree, udb, &ZONE(z)->domains); udb_ptr_new(&n, udb, &DOMAIN(d)->node); udb_rptr_zero(&DOMAIN(d)->node, udb); udb_radix_delete(udb, &dtree, &n); udb_ptr_unlink(&dtree, udb); udb_ptr_unlink(&n, udb); domain_delete(udb, d); } void udb_zone_clear(udb_base* udb, udb_ptr* zone) { udb_ptr dtree, d; assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); udb_rptr_zero(&ZONE(zone)->nsec3param, udb); udb_zone_set_log_str(udb, zone, NULL); udb_zone_set_file_str(udb, zone, NULL); /* walk and delete all domains, rrsets, rrs, but keep tree */ for(udb_radix_first(udb, &dtree, &d); d.data; udb_radix_next(udb, &d)){ udb_ptr domain; udb_ptr_new(&domain, udb, &RADNODE(&d)->elem); udb_rptr_zero(&RADNODE(&d)->elem, udb); domain_delete(udb, &domain); } udb_ptr_unlink(&d, udb); udb_radix_tree_clear(udb, &dtree); ZONE(zone)->rrset_count = 0; ZONE(zone)->rr_count = 0; ZONE(zone)->expired = 0; ZONE(zone)->mtime = 0; ZONE(zone)->mtime_nsec = 0; udb_ptr_unlink(&dtree, udb); } void udb_zone_delete(udb_base* udb, udb_ptr* zone) { udb_ptr ztree, n; udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); udb_ptr_new(&n, udb, &ZONE(zone)->node); udb_rptr_zero(&ZONE(zone)->node, udb); udb_radix_delete(udb, &ztree, &n); udb_ptr_unlink(&ztree, udb); udb_ptr_unlink(&n, udb); udb_zone_delete_plain(udb, zone); } int udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname, size_t dname_len) { udb_ptr ztree; udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); if(udb_radname_search(udb, &ztree, dname, dname_len, result)) { if(result->data) udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); udb_ptr_unlink(&ztree, udb); return (result->data != 0); } udb_ptr_unlink(&ztree, udb); return 0; } void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen, struct timespec* mtime) { udb_ptr z; if(udb_zone_search(udb, &z, dname, dlen)) { mtime->tv_sec = ZONE(&z)->mtime; mtime->tv_nsec = ZONE(&z)->mtime_nsec; udb_ptr_unlink(&z, udb); return; } mtime->tv_sec = 0; mtime->tv_nsec = 0; } void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str) { /* delete original log str (if any) */ if(ZONE(zone)->log_str.data) { udb_ptr s; size_t sz; udb_ptr_new(&s, udb, &ZONE(zone)->log_str); udb_rptr_zero(&ZONE(zone)->log_str, udb); sz = strlen((char*)udb_ptr_data(&s))+1; udb_ptr_free_space(&s, udb, sz); } /* set new log str */ if(str) { udb_ptr s; size_t sz = strlen(str)+1; if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) { return; /* failed to allocate log string */ } memmove(udb_ptr_data(&s), str, sz); udb_rptr_set_ptr(&ZONE(zone)->log_str, udb, &s); udb_ptr_unlink(&s, udb); } } void udb_zone_set_file_str(udb_base* udb, udb_ptr* zone, const char* str) { /* delete original file str (if any) */ if(ZONE(zone)->file_str.data) { udb_ptr s; size_t sz; udb_ptr_new(&s, udb, &ZONE(zone)->file_str); udb_rptr_zero(&ZONE(zone)->file_str, udb); sz = strlen((char*)udb_ptr_data(&s))+1; udb_ptr_free_space(&s, udb, sz); } /* set new file str */ if(str) { udb_ptr s; size_t sz = strlen(str)+1; if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) { return; /* failed to allocate file string */ } memmove(udb_ptr_data(&s), str, sz); udb_rptr_set_ptr(&ZONE(zone)->file_str, udb, &s); udb_ptr_unlink(&s, udb); } } const char* udb_zone_get_file_str(udb_base* udb, const uint8_t* dname, size_t dlen) { udb_ptr z; if(udb_zone_search(udb, &z, dname, dlen)) { const char* str; if(ZONE(&z)->file_str.data) { udb_ptr s; udb_ptr_new(&s, udb, &ZONE(&z)->file_str); str = (const char*)udb_ptr_data(&s); udb_ptr_unlink(&s, udb); } else str = NULL; udb_ptr_unlink(&z, udb); return str; } return NULL; } #ifdef NSEC3 /** select the nsec3param for nsec3 usage */ static void select_nsec3_param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) { udb_ptr rr; udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); while(rr.data) { if(RR(&rr)->len >= 5 && RR(&rr)->wire[0] == NSEC3_SHA1_HASH && RR(&rr)->wire[1] == 0) { udb_rptr_set_ptr(&ZONE(zone)->nsec3param, udb, &rr); udb_ptr_unlink(&rr, udb); return; } udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); } udb_ptr_unlink(&rr, udb); } const char* udb_nsec3param_string(udb_ptr* rr) { /* max saltlenth plus first couple of numbers (3+1+5+1+3+1) */ static char params[MAX_RDLENGTH*2+16]; char* p; assert(RR(rr)->len >= 5); p = params + snprintf(params, sizeof(params), "%u %u %u ", (unsigned)RR(rr)->wire[0], (unsigned)RR(rr)->wire[1], (unsigned)read_uint16(&RR(rr)->wire[2])); if(RR(rr)->wire[4] == 0) { *p++ = '-'; } else { assert(RR(rr)->len >= 5+RR(rr)->wire[4]); p += hex_ntop(&RR(rr)->wire[5], RR(rr)->wire[4], p, sizeof(params)-strlen(params)-1); } *p = 0; return params; } /** look in zone for new selected nsec3param record from rrset */ static void zone_hash_nsec3param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) { select_nsec3_param(udb, zone, rrset); if(ZONE(zone)->nsec3param.data == 0) return; /* prettyprint the nsec3 parameters we are using */ if(2 <= verbosity) { udb_ptr par; udb_ptr_new(&par, udb, &ZONE(zone)->nsec3param); VERBOSITY(1, (LOG_INFO, "rehash of zone %s with parameters %s", wiredname2str(ZONE(zone)->name), udb_nsec3param_string(&par))); udb_ptr_unlink(&par, udb); } } #endif /* NSEC3 */ /** create a new domain name */ static int domain_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, udb_ptr* result) { udb_ptr dtree, node; /* create domain chunk */ if(!udb_ptr_alloc_space(result, udb, udb_chunk_type_domain, sizeof(struct domain_d)+nmlen)) return 0; udb_rel_ptr_init(&DOMAIN(result)->node); udb_rel_ptr_init(&DOMAIN(result)->rrsets); DOMAIN(result)->namelen = nmlen; memmove(DOMAIN(result)->name, nm, nmlen); /* insert into domain tree */ udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); if(!udb_radname_insert(udb, &dtree, nm, nmlen, result, &node)) { udb_ptr_free_space(result, udb, sizeof(struct domain_d)+nmlen); udb_ptr_unlink(&dtree, udb); return 0; } udb_rptr_set_ptr(&DOMAIN(result)->node, udb, &node); udb_ptr_unlink(&dtree, udb); udb_ptr_unlink(&node, udb); return 1; } int udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, udb_ptr* result) { int r; udb_ptr dtree; assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); r = udb_radname_search(udb, &dtree, nm, nmlen, result); if(result->data) udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); udb_ptr_unlink(&dtree, udb); return r && result->data; } /** find or create a domain name in the zone domain tree */ static int domain_find_or_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, udb_ptr* result) { assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); if(udb_domain_find(udb, zone, nm, nmlen, result)) return 1; return domain_create(udb, zone, nm, nmlen, result); } /** remove rrset from the domain name rrset-list */ static void domain_remove_rrset(udb_base* udb, udb_ptr* domain, uint16_t t) { udb_ptr p, prev; assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); udb_ptr_init(&prev, udb); while(p.data) { if(RRSET(&p)->type == t) { /* remove it */ if(prev.data == 0) { /* first rrset */ udb_rptr_set_rptr(&DOMAIN(domain)->rrsets, udb, &RRSET(&p)->next); } else { udb_rptr_set_rptr(&RRSET(&prev)->next, udb, &RRSET(&p)->next); } udb_ptr_unlink(&prev, udb); rrset_delete(udb, &p); return; } udb_ptr_set_ptr(&prev, udb, &p); udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); } /* rrset does not exist */ udb_ptr_unlink(&prev, udb); udb_ptr_unlink(&p, udb); } /** create rrset in the domain rrset list */ static int rrset_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) { /* create it */ if(!udb_ptr_alloc_space(res, udb, udb_chunk_type_rrset, sizeof(struct rrset_d))) return 0; udb_rel_ptr_init(&RRSET(res)->next); udb_rel_ptr_init(&RRSET(res)->rrs); RRSET(res)->type = t; #if 0 /* link it in, at the front */ udb_rptr_set_rptr(&RRSET(res)->next, udb, &DOMAIN(domain)->rrsets); udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); #else /* preserve RRset order, link at end */ if(DOMAIN(domain)->rrsets.data == 0) { udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); } else { udb_ptr p; udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); while(RRSET(&p)->next.data) udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); udb_rptr_set_ptr(&RRSET(&p)->next, udb, res); udb_ptr_unlink(&p, udb); } #endif return 1; } int udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) { assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); udb_ptr_init(res, udb); udb_ptr_set_rptr(res, udb, &DOMAIN(domain)->rrsets); while(res->data) { if(RRSET(res)->type == t) return 1; udb_ptr_set_rptr(res, udb, &RRSET(res)->next); } /* rrset does not exist and res->data is conveniently zero */ return 0; } /** find or create rrset in the domain rrset list */ static int rrset_find_or_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) { if(udb_rrset_find(udb, domain, t, res)) return 1; return rrset_create(udb, domain, t, res); } /** see if RR matches type, class and rdata */ static int rr_match(udb_ptr* rr, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) { return RR(rr)->type == t && RR(rr)->klass == k && RR(rr)->len == rdatalen && memcmp(RR(rr)->wire, rdata, rdatalen) == 0; } /** see if RR exists in the RR list that matches the rdata, and return it */ static int rr_search(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen, udb_ptr* result) { assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); udb_ptr_init(result, udb); udb_ptr_set_rptr(result, udb, &RRSET(rrset)->rrs); while(result->data) { if(rr_match(result, t, k, rdata, rdatalen)) return 1; /* found */ udb_ptr_set_rptr(result, udb, &RR(result)->next); } /* not found and result->data is conveniently zero */ return 0; } /** create RR chunk */ static int rr_create(udb_base* udb, uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen, udb_ptr* rr) { if(!udb_ptr_alloc_space(rr, udb, udb_chunk_type_rr, sizeof(struct rr_d)+rdatalen)) return 0; udb_rel_ptr_init(&RR(rr)->next); RR(rr)->type = t; RR(rr)->klass = k; RR(rr)->ttl = ttl; RR(rr)->len = rdatalen; memmove(RR(rr)->wire, rdata, rdatalen); return 1; } /** add an RR to an RRset. */ static int rrset_add_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen) { udb_ptr rr; assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); /* create it */ if(!rr_create(udb, t, k, ttl, rdata, rdatalen, &rr)) return 0; /* add at end, to preserve order of RRs */ if(RRSET(rrset)->rrs.data == 0) { udb_rptr_set_ptr(&RRSET(rrset)->rrs, udb, &rr); } else { udb_ptr lastrr; udb_ptr_new(&lastrr, udb, &RRSET(rrset)->rrs); while(RR(&lastrr)->next.data) udb_ptr_set_rptr(&lastrr, udb, &RR(&lastrr)->next); udb_rptr_set_ptr(&RR(&lastrr)->next, udb, &rr); udb_ptr_unlink(&lastrr, udb); } udb_ptr_unlink(&rr, udb); return 1; } /** remove an RR from an RRset. return 0 if RR did not exist. */ static int rrset_del_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) { udb_ptr p, prev; assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); udb_ptr_new(&p, udb, &RRSET(rrset)->rrs); udb_ptr_init(&prev, udb); while(p.data) { if(rr_match(&p, t, k, rdata, rdatalen)) { /* remove it */ if(prev.data == 0) { /* first in list */ udb_rptr_set_rptr(&RRSET(rrset)->rrs, udb, &RR(&p)->next); } else { udb_rptr_set_rptr(&RR(&prev)->next, udb, &RR(&p)->next); } udb_ptr_unlink(&prev, udb); rr_delete(udb, &p); return 1; } udb_ptr_set_ptr(&prev, udb, &p); udb_ptr_set_rptr(&p, udb, &RR(&p)->next); } /* not found */ udb_ptr_unlink(&prev, udb); udb_ptr_unlink(&p, udb); return 0; } int udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen) { udb_ptr domain, rrset, rr; int created_rrset = 0; assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); /* find or create domain */ if(!domain_find_or_create(udb, zone, nm, nmlen, &domain)) { return 0; } /* find or create rrset(type) */ if(!rrset_find_or_create(udb, &domain, t, &rrset)) { goto exit_clean_domain; } if(RRSET(&rrset)->rrs.data == 0) created_rrset = 1; /* test for duplicate RRs */ if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { udb_ptr_unlink(&rr, udb); goto exit_clean_domain_rrset; } /* add RR to rrset */ if(!rrset_add_rr(udb, &rrset, t, k, ttl, rdata, rdatalen)) { exit_clean_domain_rrset: /* if rrset was created, remove it */ if(RRSET(&rrset)->rrs.data == 0) { udb_ptr_zero(&rrset, udb); domain_remove_rrset(udb, &domain, t); } udb_ptr_unlink(&rrset, udb); exit_clean_domain: /* if domain created, delete it */ if(DOMAIN(&domain)->rrsets.data == 0) domain_delete_unlink(udb, zone, &domain); udb_ptr_unlink(&domain, udb); return 0; } /* success, account changes */ if(created_rrset) ZONE(zone)->rrset_count ++; ZONE(zone)->rr_count ++; #ifdef NSEC3 if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0) zone_hash_nsec3param(udb, zone, &rrset); #endif /* NSEC3 */ udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); return 1; } void udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) { udb_ptr domain, rrset; assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); /* find the domain */ if(!udb_domain_find(udb, zone, nm, nmlen, &domain)) return; /* find the rrset */ if(!udb_rrset_find(udb, &domain, t, &rrset)) { udb_ptr_unlink(&domain, udb); return; } /* remove the RR */ #ifdef NSEC3 if(t == TYPE_NSEC3PARAM) { udb_ptr rr; if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { if(rr.data == ZONE(zone)->nsec3param.data) { udb_rptr_zero(&ZONE(zone)->nsec3param, udb); } udb_ptr_unlink(&rr, udb); } } #endif /* NSEC3 */ if(!rrset_del_rr(udb, &rrset, t, k, rdata, rdatalen)) { /* rr did not exist */ udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); return; } ZONE(zone)->rr_count --; #ifdef NSEC3 if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0 && RRSET(&rrset)->rrs.data != 0) { zone_hash_nsec3param(udb, zone, &rrset); } #endif /* NSEC3 */ /* see we we can remove the rrset too */ if(RRSET(&rrset)->rrs.data == 0) { udb_ptr_zero(&rrset, udb); domain_remove_rrset(udb, &domain, t); ZONE(zone)->rrset_count --; } /* see if we can remove the domain name too */ if(DOMAIN(&domain)->rrsets.data == 0) { domain_delete_unlink(udb, zone, &domain); } udb_ptr_unlink(&rrset, udb); udb_ptr_unlink(&domain, udb); } void udb_zone_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct zone_d* p = (struct zone_d*)d; assert(s >= sizeof(struct zone_d)+p->namelen); (void)s; (*cb)(base, &p->node, arg); (*cb)(base, &p->domains, arg); (*cb)(base, &p->nsec3param, arg); (*cb)(base, &p->log_str, arg); (*cb)(base, &p->file_str, arg); } void udb_domain_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct domain_d* p = (struct domain_d*)d; assert(s >= sizeof(struct domain_d)+p->namelen); (void)s; (*cb)(base, &p->node, arg); (*cb)(base, &p->rrsets, arg); } void udb_rrset_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct rrset_d* p = (struct rrset_d*)d; assert(s >= sizeof(struct rrset_d)); (void)s; (*cb)(base, &p->next, arg); (*cb)(base, &p->rrs, arg); } void udb_rr_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct rr_d* p = (struct rr_d*)d; assert(s >= sizeof(struct rr_d)+p->len); (void)s; (*cb)(base, &p->next, arg); } void udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct task_list_d* p = (struct task_list_d*)d; assert(s >= p->size); (void)s; (*cb)(base, &p->next, arg); } void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { (void)warg; switch(t) { case udb_chunk_type_radtree: udb_radix_tree_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_radnode: udb_radix_node_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_radarray: udb_radix_array_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_zone: udb_zone_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_domain: udb_domain_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_rrset: udb_rrset_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_rr: udb_rr_walk_chunk(base, d, s, cb, arg); break; case udb_chunk_type_task: udb_task_walk_chunk(base, d, s, cb, arg); break; default: /* no rel ptrs */ break; } } nsd-4.1.26/rbtree.h0000664000175000017500000000457513151255754013505 0ustar wouterwouter/* * rbtree.h -- generic red-black tree * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _RBTREE_H_ #define _RBTREE_H_ #include "region-allocator.h" /* * This structure must be the first member of the data structure in * the rbtree. This allows easy casting between an rbnode_type and the * user data (poor man's inheritance). */ typedef struct rbnode rbnode_type; struct rbnode { rbnode_type *parent; rbnode_type *left; rbnode_type *right; const void *key; uint8_t color; } ATTR_PACKED; #define RBTREE_NULL &rbtree_null_node extern rbnode_type rbtree_null_node; typedef struct rbtree rbtree_type; struct rbtree { region_type *region; /* The root of the red-black tree */ rbnode_type *root; /* The number of the nodes in the tree */ size_t count; /* Current node for walks... */ rbnode_type *_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 *)); rbnode_type *rbtree_insert(rbtree_type *rbtree, rbnode_type *data); /* returns node that is now unlinked from the tree. User to delete it. * returns 0 if node not present */ rbnode_type *rbtree_delete(rbtree_type *rbtree, const void *key); rbnode_type *rbtree_search(rbtree_type *rbtree, const void *key); /* returns true if exact match in result. Else result points to <= element, or NULL if key is smaller than the smallest key. */ int rbtree_find_less_equal(rbtree_type *rbtree, const void *key, rbnode_type **result); rbnode_type *rbtree_first(rbtree_type *rbtree); rbnode_type *rbtree_last(rbtree_type *rbtree); rbnode_type *rbtree_next(rbnode_type *rbtree); rbnode_type *rbtree_previous(rbnode_type *rbtree); #define RBTREE_WALK(rbtree, k, d) \ for((rbtree)->_node = rbtree_first(rbtree);\ (rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \ ((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node)) /* call with node=variable of struct* with rbnode_type as first element. with type is the type of a pointer to that struct. */ #define RBTREE_FOR(node, type, rbtree) \ for(node=(type)rbtree_first(rbtree); \ (rbnode_type*)node != RBTREE_NULL; \ node = (type)rbtree_next((rbnode_type*)node)) #endif /* _RBTREE_H_ */ nsd-4.1.26/udbradtree.c0000664000175000017500000012660513040156013014316 0ustar wouterwouter/* * udbradtree -- radix tree for binary strings for in udb file. * * Copyright (c) 2011, NLnet Labs. See LICENSE for license. */ #include "config.h" #include #include #include #include "udbradtree.h" #include "radtree.h" #define RADARRAY(ptr) ((struct udb_radarray_d*)UDB_PTR(ptr)) /** see if radarray can be reduced (by a factor of two) */ static int udb_radarray_reduce_if_needed(udb_base* udb, udb_ptr* n); int udb_radix_tree_create(udb_base* udb, udb_ptr* ptr) { if(!udb_ptr_alloc_space(ptr, udb, udb_chunk_type_radtree, sizeof(struct udb_radtree_d))) return 0; udb_rel_ptr_init(&RADTREE(ptr)->root); RADTREE(ptr)->count = 0; return 1; } /** size of radarray */ static size_t size_of_radarray(struct udb_radarray_d* a) { return sizeof(struct udb_radarray_d)+((size_t)a->capacity)*( sizeof(struct udb_radsel_d)+(size_t)a->str_cap); } /** size in bytes of data in the array lookup structure */ static size_t size_of_lookup(udb_ptr* node) { assert(udb_ptr_get_type(node) == udb_chunk_type_radnode); return size_of_radarray((struct udb_radarray_d*)UDB_REL(*node->base, RADNODE(node)->lookup.data)); } /** external variant, size in bytes of data in the array lookup structure */ size_t size_of_lookup_ext(udb_ptr* lookup) { return size_of_lookup(lookup); } /** size needed for a lookup array like this */ static size_t size_of_lookup_needed(uint16_t capacity, udb_radstrlen_type str_cap) { return sizeof(struct udb_radarray_d)+ ((size_t)capacity)*( sizeof(struct udb_radsel_d)+(size_t)str_cap); } /** get the lookup array for a node */ static struct udb_radarray_d* lookup(udb_ptr* n) { assert(udb_ptr_get_type(n) == udb_chunk_type_radnode); return (struct udb_radarray_d*)UDB_REL(*n->base, RADNODE(n)->lookup.data); } /** get a length in the lookup array */ static udb_radstrlen_type lookup_len(udb_ptr* n, unsigned i) { return lookup(n)->array[i].len; } /** get a string in the lookup array */ static uint8_t* lookup_string(udb_ptr* n, unsigned i) { return ((uint8_t*)&(lookup(n)->array[lookup(n)->capacity]))+ i*lookup(n)->str_cap; } /** get a node in the lookup array */ static struct udb_radnode_d* lookup_node(udb_ptr* n, unsigned i) { return (struct udb_radnode_d*)UDB_REL(*n->base, lookup(n)->array[i].node.data); } /** zero the relptrs in radarray */ static void udb_radarray_zero_ptrs(udb_base* udb, udb_ptr* n) { unsigned i; for(i=0; ilen; i++) { udb_rptr_zero(&lookup(n)->array[i].node, udb); } } /** delete a radnode */ static void udb_radnode_delete(udb_base* udb, udb_ptr* n) { if(udb_ptr_is_null(n)) return; if(RADNODE(n)->lookup.data) { udb_radarray_zero_ptrs(udb, n); udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); } udb_rptr_zero(&RADNODE(n)->lookup, udb); udb_rptr_zero(&RADNODE(n)->parent, udb); udb_rptr_zero(&RADNODE(n)->elem, udb); udb_ptr_free_space(n, udb, sizeof(struct udb_radnode_d)); } /** delete radnodes in postorder recursion, n is ptr to node */ static void udb_radnode_del_postorder(udb_base* udb, udb_ptr* n) { unsigned i; udb_ptr sub; if(udb_ptr_is_null(n)) return; /* clear subnodes */ udb_ptr_init(&sub, udb); for(i=0; ilen; i++) { udb_ptr_set_rptr(&sub, udb, &lookup(n)->array[i].node); udb_rptr_zero(&lookup(n)->array[i].node, udb); udb_radnode_del_postorder(udb, &sub); } udb_ptr_unlink(&sub, udb); /* clear lookup */ udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); udb_rptr_zero(&RADNODE(n)->parent, udb); udb_rptr_zero(&RADNODE(n)->elem, udb); udb_ptr_free_space(n, udb, sizeof(struct udb_radnode_d)); } void udb_radix_tree_clear(udb_base* udb, udb_ptr* rt) { udb_ptr root; udb_ptr_new(&root, udb, &RADTREE(rt)->root); udb_rptr_zero(&RADTREE(rt)->root, udb); /* free the root node (and its descendants, if any) */ udb_radnode_del_postorder(udb, &root); udb_ptr_unlink(&root, udb); RADTREE(rt)->count = 0; } void udb_radix_tree_delete(udb_base* udb, udb_ptr* rt) { if(rt->data == 0) return; assert(udb_ptr_get_type(rt) == udb_chunk_type_radtree); udb_radix_tree_clear(udb, rt); udb_ptr_free_space(rt, udb, sizeof(struct udb_radtree_d)); } /** * Find a prefix of the key, in whole-nodes. * Finds the longest prefix that corresponds to a whole radnode entry. * There may be a slightly longer prefix in one of the array elements. * @param result: the longest prefix, the entry itself if *respos==len, * otherwise an array entry, residx. Output. * @param respos: pos in string where next unmatched byte is, if == len an * exact match has been found. If == 0 then a "" match was found. * @return false if no prefix found, not even the root "" prefix. */ static int udb_radix_find_prefix_node(udb_base* udb, udb_ptr* rt, uint8_t* k, udb_radstrlen_type len, udb_ptr* result, udb_radstrlen_type* respos) { udb_radstrlen_type pos = 0; uint8_t byte; udb_ptr n; udb_ptr_new(&n, udb, &RADTREE(rt)->root); *respos = 0; udb_ptr_set_ptr(result, udb, &n); if(udb_ptr_is_null(&n)) { udb_ptr_unlink(&n, udb); return 0; } while(!udb_ptr_is_null(&n)) { if(pos == len) { break; } byte = k[pos]; if(byte < RADNODE(&n)->offset) { break; } byte -= RADNODE(&n)->offset; if(byte >= lookup(&n)->len) { break; } pos++; if(lookup(&n)->array[byte].len != 0) { /* must match additional string */ if(pos+lookup(&n)->array[byte].len > len) { break; } if(memcmp(&k[pos], lookup_string(&n, byte), lookup(&n)->array[byte].len) != 0) { break; } pos += lookup(&n)->array[byte].len; } udb_ptr_set_rptr(&n, udb, &lookup(&n)->array[byte].node); if(udb_ptr_is_null(&n)) { break; } *respos = pos; udb_ptr_set_ptr(result, udb, &n); } udb_ptr_unlink(&n, udb); return 1; } /** grow the radnode stringcapacity, copy existing elements */ static int udb_radnode_str_grow(udb_base* udb, udb_ptr* n, udb_radstrlen_type want) { unsigned ns = ((unsigned)lookup(n)->str_cap)*2; unsigned i; udb_ptr a; if(want > ns) ns = want; if(ns > 65535) ns = 65535; /* MAX of udb_radstrlen_type range */ /* if this fails, the tree is still usable */ if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, size_of_lookup_needed(lookup(n)->capacity, ns))) return 0; /* make sure to zero the newly allocated relptrs to init them */ memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); RADARRAY(&a)->str_cap = ns; for(i = 0; i < lookup(n)->len; i++) { udb_rel_ptr_init(&RADARRAY(&a)->array[i].node); udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, &lookup(n)->array[i].node); RADARRAY(&a)->array[i].len = lookup_len(n, i); memmove(((uint8_t*)(&RADARRAY(&a)->array[ lookup(n)->capacity]))+i*ns, lookup_string(n, i), lookup(n)->str_cap); } udb_radarray_zero_ptrs(udb, n); udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); udb_ptr_unlink(&a, udb); return 1; } /** grow the radnode array, copy existing elements to start of new array */ static int udb_radnode_array_grow(udb_base* udb, udb_ptr* n, size_t want) { unsigned i; unsigned ns = ((unsigned)lookup(n)->capacity)*2; udb_ptr a; assert(want <= 256); /* cannot be more, range of uint8 */ if(want > ns) ns = want; if(ns > 256) ns = 256; /* if this fails, the tree is still usable */ if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, size_of_lookup_needed(ns, lookup(n)->str_cap))) return 0; /* zero the newly allocated rel ptrs to init them */ memset(UDB_PTR(&a), 0, size_of_lookup_needed(ns, lookup(n)->str_cap)); assert(lookup(n)->len <= lookup(n)->capacity); assert(lookup(n)->capacity < ns); memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); RADARRAY(&a)->capacity = ns; for(i=0; ilen; i++) { udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, &lookup(n)->array[i].node); RADARRAY(&a)->array[i].len = lookup_len(n, i); } memmove(&RADARRAY(&a)->array[ns], lookup_string(n, 0), lookup(n)->len * lookup(n)->str_cap); udb_radarray_zero_ptrs(udb, n); udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); udb_ptr_unlink(&a, udb); return 1; } /** make empty array in radnode */ static int udb_radnode_array_create(udb_base* udb, udb_ptr* n) { /* is there an array? */ if(RADNODE(n)->lookup.data == 0) { /* create array */ udb_ptr a; uint16_t cap = 0; udb_radstrlen_type len = 0; if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, size_of_lookup_needed(cap, len))) return 0; memset(UDB_PTR(&a), 0, size_of_lookup_needed(cap, len)); udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); RADARRAY(&a)->len = cap; RADARRAY(&a)->capacity = cap; RADARRAY(&a)->str_cap = len; RADNODE(n)->offset = 0; udb_ptr_unlink(&a, udb); } return 1; } /** make space in radnode for another byte, or longer strings */ static int udb_radnode_array_space(udb_base* udb, udb_ptr* n, uint8_t byte, udb_radstrlen_type len) { /* is there an array? */ if(RADNODE(n)->lookup.data == 0) { /* create array */ udb_ptr a; uint16_t cap = 1; if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, size_of_lookup_needed(cap, len))) return 0; /* this memset inits the relptr that is allocated */ memset(UDB_PTR(&a), 0, size_of_lookup_needed(cap, len)); udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); RADARRAY(&a)->len = cap; RADARRAY(&a)->capacity = cap; RADARRAY(&a)->str_cap = len; RADNODE(n)->offset = byte; udb_ptr_unlink(&a, udb); return 1; } if(lookup(n)->capacity == 0) { if(!udb_radnode_array_grow(udb, n, 1)) return 0; } /* make space for this stringsize */ if(lookup(n)->str_cap < len) { /* must resize for stringsize */ if(!udb_radnode_str_grow(udb, n, len)) return 0; } /* other cases */ /* is the array unused? */ if(lookup(n)->len == 0 && lookup(n)->capacity != 0) { lookup(n)->len = 1; RADNODE(n)->offset = byte; memset(&lookup(n)->array[0], 0, sizeof(struct udb_radsel_d)); /* is it below the offset? */ } else if(byte < RADNODE(n)->offset) { /* is capacity enough? */ int i; unsigned need = RADNODE(n)->offset-byte; if(lookup(n)->len+need > lookup(n)->capacity) { /* grow array */ if(!udb_radnode_array_grow(udb, n, lookup(n)->len+need)) return 0; } /* take a piece of capacity into use, init the relptrs */ for(i = lookup(n)->len; i< (int)(lookup(n)->len + need); i++) { udb_rel_ptr_init(&lookup(n)->array[i].node); } /* reshuffle items to end */ for(i = lookup(n)->len-1; i >= 0; i--) { udb_rptr_set_rptr(&lookup(n)->array[need+i].node, udb, &lookup(n)->array[i].node); lookup(n)->array[need+i].len = lookup_len(n, i); /* fixup pidx */ if(lookup(n)->array[i+need].node.data) lookup_node(n, i+need)->pidx = i+need; } memmove(lookup_string(n, need), lookup_string(n, 0), lookup(n)->len*lookup(n)->str_cap); /* zero the first */ for(i = 0; i < (int)need; i++) { udb_rptr_zero(&lookup(n)->array[i].node, udb); lookup(n)->array[i].len = 0; } lookup(n)->len += need; RADNODE(n)->offset = byte; /* is it above the max? */ } else if(byte - RADNODE(n)->offset >= lookup(n)->len) { /* is capacity enough? */ int i; unsigned need = (byte-RADNODE(n)->offset) - lookup(n)->len + 1; /* grow array */ if(lookup(n)->len + need > lookup(n)->capacity) { if(!udb_radnode_array_grow(udb, n, lookup(n)->len+need)) return 0; } /* take new entries into use, init relptrs */ for(i = lookup(n)->len; i< (int)(lookup(n)->len + need); i++) { udb_rel_ptr_init(&lookup(n)->array[i].node); lookup(n)->array[i].len = 0; } /* grow length */ lookup(n)->len += need; } return 1; } /** make space for string size */ static int udb_radnode_str_space(udb_base* udb, udb_ptr* n, udb_radstrlen_type len) { if(RADNODE(n)->lookup.data == 0) { return udb_radnode_array_space(udb, n, 0, len); } if(lookup(n)->str_cap < len) { /* must resize for stringsize */ if(!udb_radnode_str_grow(udb, n, len)) return 0; } return 1; } /** copy remainder from prefixes for a split: * plen: len prefix, l: longer bstring, llen: length of l. */ static void udb_radsel_prefix_remainder(udb_radstrlen_type plen, uint8_t* l, udb_radstrlen_type llen, uint8_t* s, udb_radstrlen_type* slen) { *slen = llen - plen; /* assert(*slen <= lookup(n)->str_cap); */ memmove(s, l+plen, llen-plen); } /** create a prefix in the array strs */ static void udb_radsel_str_create(uint8_t* s, udb_radstrlen_type* slen, uint8_t* k, udb_radstrlen_type pos, udb_radstrlen_type len) { *slen = len-pos; /* assert(*slen <= lookup(n)->str_cap); */ memmove(s, k+pos, len-pos); } static udb_radstrlen_type udb_bstr_common(uint8_t* x, udb_radstrlen_type xlen, uint8_t* y, udb_radstrlen_type ylen) { assert(sizeof(radstrlen_type) == sizeof(udb_radstrlen_type)); return bstr_common_ext(x, xlen, y, ylen); } static int udb_bstr_is_prefix(uint8_t* p, udb_radstrlen_type plen, uint8_t* x, udb_radstrlen_type xlen) { assert(sizeof(radstrlen_type) == sizeof(udb_radstrlen_type)); return bstr_is_prefix_ext(p, plen, x, xlen); } /** grow array space for byte N after a string, (but if string shorter) */ static int udb_radnode_array_space_strremain(udb_base* udb, udb_ptr* n, uint8_t* str, udb_radstrlen_type len, udb_radstrlen_type pos) { assert(pos < len); /* shift by one char because it goes in lookup array */ return udb_radnode_array_space(udb, n, str[pos], len-(pos+1)); } /** radsel create a split when two nodes have shared prefix. * @param udb: udb * @param n: node with the radsel that gets changed, it contains a node. * @param idx: the index of the radsel that gets changed. * @param k: key byte string * @param pos: position where the string enters the radsel (e.g. r.str) * @param len: length of k. * @param add: additional node for the string k. * removed by called on failure. * @return false on alloc failure, no changes made. */ static int udb_radsel_split(udb_base* udb, udb_ptr* n, uint8_t idx, uint8_t* k, udb_radstrlen_type pos, udb_radstrlen_type len, udb_ptr* add) { uint8_t* addstr = k+pos; udb_radstrlen_type addlen = len-pos; if(udb_bstr_is_prefix(addstr, addlen, lookup_string(n, idx), lookup_len(n, idx))) { udb_radstrlen_type split_len = 0; /* 'add' is a prefix of r.node */ /* also for empty addstr */ /* set it up so that the 'add' node has r.node as child */ /* so, r.node gets moved below the 'add' node, but we do * this so that the r.node stays the same pointer for its * key name */ assert(addlen != lookup_len(n, idx)); assert(addlen < lookup_len(n, idx)); /* make space for new string sizes */ if(!udb_radnode_str_space(udb, n, addlen)) return 0; if(lookup_len(n, idx) - addlen > 1) /* shift one because a char is in the lookup array */ split_len = lookup_len(n, idx) - (addlen+1); if(!udb_radnode_array_space(udb, add, lookup_string(n, idx)[addlen], split_len)) return 0; /* alloc succeeded, now link it in */ udb_rptr_set_rptr(&RADNODE(add)->parent, udb, &lookup_node(n, idx)->parent); RADNODE(add)->pidx = lookup_node(n, idx)->pidx; udb_rptr_set_rptr(&lookup(add)->array[0].node, udb, &lookup(n)->array[idx].node); if(lookup_len(n, idx) - addlen > 1) { udb_radsel_prefix_remainder(addlen+1, lookup_string(n, idx), lookup_len(n, idx), lookup_string(add, 0), &lookup(add)->array[0].len); } else { lookup(add)->array[0].len = 0; } udb_rptr_set_ptr(&lookup_node(n, idx)->parent, udb, add); lookup_node(n, idx)->pidx = 0; udb_rptr_set_ptr(&lookup(n)->array[idx].node, udb, add); memmove(lookup_string(n, idx), addstr, addlen); lookup(n)->array[idx].len = addlen; /* n's string may have become shorter */ if(!udb_radarray_reduce_if_needed(udb, n)) { /* ignore this, our tree has become inefficient */ } } else if(udb_bstr_is_prefix(lookup_string(n, idx), lookup_len(n, idx), addstr, addlen)) { udb_radstrlen_type split_len = 0; udb_ptr rnode; /* r.node is a prefix of 'add' */ /* set it up so that the 'r.node' has 'add' as child */ /* and basically, r.node is already completely fine, * we only need to create a node as its child */ assert(addlen != lookup_len(n, idx)); assert(lookup_len(n, idx) < addlen); udb_ptr_new(&rnode, udb, &lookup(n)->array[idx].node); /* make space for string length */ if(addlen-lookup_len(n, idx) > 1) { /* shift one because a character goes into array */ split_len = addlen - (lookup_len(n, idx)+1); } if(!udb_radnode_array_space(udb, &rnode, addstr[lookup_len(n, idx)], split_len)) { udb_ptr_unlink(&rnode, udb); return 0; } /* alloc succeeded, now link it in */ udb_rptr_set_ptr(&RADNODE(add)->parent, udb, &rnode); RADNODE(add)->pidx = addstr[lookup_len(n, idx)] - RADNODE(&rnode)->offset; udb_rptr_set_ptr(&lookup(&rnode)->array[ RADNODE(add)->pidx ] .node, udb, add); if(addlen-lookup_len(n, idx) > 1) { udb_radsel_prefix_remainder(lookup_len(n, idx)+1, addstr, addlen, lookup_string(&rnode, RADNODE(add)->pidx), &lookup(&rnode)->array[ RADNODE(add)->pidx] .len); } else { lookup(&rnode)->array[ RADNODE(add)->pidx].len = 0; } /* rnode's string has become shorter */ if(!udb_radarray_reduce_if_needed(udb, &rnode)) { /* ignore this, our tree has become inefficient */ } udb_ptr_unlink(&rnode, udb); } else { /* okay we need to create a new node that chooses between * the nodes 'add' and r.node * We do this so that r.node stays the same pointer for its * key name. */ udb_ptr com, rnode; udb_radstrlen_type common_len = udb_bstr_common( lookup_string(n, idx), lookup_len(n, idx), addstr, addlen); assert(common_len < lookup_len(n, idx)); assert(common_len < addlen); udb_ptr_new(&rnode, udb, &lookup(n)->array[idx].node); /* create the new node for choice */ if(!udb_ptr_alloc_space(&com, udb, udb_chunk_type_radnode, sizeof(struct udb_radnode_d))) { udb_ptr_unlink(&rnode, udb); return 0; /* out of space */ } memset(UDB_PTR(&com), 0, sizeof(struct udb_radnode_d)); /* make stringspace for the two substring choices */ /* this allocates the com->lookup array */ if(!udb_radnode_array_space_strremain(udb, &com, lookup_string(n, idx), lookup_len(n, idx), common_len) || !udb_radnode_array_space_strremain(udb, &com, addstr, addlen, common_len)) { udb_ptr_unlink(&rnode, udb); udb_radnode_delete(udb, &com); return 0; } /* create stringspace for the shared prefix */ if(common_len > 0) { if(!udb_radnode_str_space(udb, n, common_len-1)) { udb_ptr_unlink(&rnode, udb); udb_radnode_delete(udb, &com); return 0; } } /* allocs succeeded, proceed to link it all up */ udb_rptr_set_rptr(&RADNODE(&com)->parent, udb, &RADNODE(&rnode)->parent); RADNODE(&com)->pidx = RADNODE(&rnode)->pidx; udb_rptr_set_ptr(&RADNODE(&rnode)->parent, udb, &com); RADNODE(&rnode)->pidx = lookup_string(n, idx)[common_len] - RADNODE(&com)->offset; udb_rptr_set_ptr(&RADNODE(add)->parent, udb, &com); RADNODE(add)->pidx = addstr[common_len] - RADNODE(&com)->offset; udb_rptr_set_ptr(&lookup(&com)->array[RADNODE(&rnode)->pidx] .node, udb, &rnode); if(lookup_len(n, idx)-common_len > 1) { udb_radsel_prefix_remainder(common_len+1, lookup_string(n, idx), lookup_len(n, idx), lookup_string(&com, RADNODE(&rnode)->pidx), &lookup(&com)->array[RADNODE(&rnode)->pidx].len); } else { lookup(&com)->array[RADNODE(&rnode)->pidx].len= 0; } udb_rptr_set_ptr(&lookup(&com)->array[RADNODE(add)->pidx] .node, udb, add); if(addlen-common_len > 1) { udb_radsel_prefix_remainder(common_len+1, addstr, addlen, lookup_string(&com, RADNODE(add)->pidx), &lookup(&com)->array[RADNODE(add)->pidx].len); } else { lookup(&com)->array[RADNODE(add)->pidx].len = 0; } memmove(lookup_string(n, idx), addstr, common_len); lookup(n)->array[idx].len = common_len; udb_rptr_set_ptr(&lookup(n)->array[idx].node, udb, &com); udb_ptr_unlink(&rnode, udb); udb_ptr_unlink(&com, udb); /* n's string has become shorter */ if(!udb_radarray_reduce_if_needed(udb, n)) { /* ignore this, our tree has become inefficient */ } } return 1; } uint64_t* result_data = NULL; udb_void udb_radix_insert(udb_base* udb, udb_ptr* rt, uint8_t* k, udb_radstrlen_type len, udb_ptr* elem, udb_ptr* result) { udb_void ret; udb_ptr add, n; /* type udb_radnode_d */ udb_radstrlen_type pos = 0; /* create new element to add */ if(!udb_ptr_alloc_space(&add, udb, udb_chunk_type_radnode, sizeof(struct udb_radnode_d))) { return 0; /* alloc failure */ } memset(UDB_PTR(&add), 0, sizeof(struct udb_radnode_d)); udb_rptr_set_ptr(&RADNODE(&add)->elem, udb, elem); if(!udb_radnode_array_create(udb, &add)) { udb_ptr_free_space(&add, udb, sizeof(struct udb_radnode_d)); return 0; /* alloc failure */ } udb_ptr_init(&n, udb); result_data = &n.data; /* find out where to add it */ if(!udb_radix_find_prefix_node(udb, rt, k, len, &n, &pos)) { /* new root */ assert(RADTREE(rt)->root.data == 0); if(len == 0) { udb_rptr_set_ptr(&RADTREE(rt)->root, udb, &add); } else { /* add a root to point to new node */ udb_ptr_zero(&n, udb); if(!udb_ptr_alloc_space(&n, udb, udb_chunk_type_radnode, sizeof(struct udb_radnode_d))) { udb_radnode_delete(udb, &add); udb_ptr_unlink(&n, udb); return 0; /* alloc failure */ } memset(RADNODE(&n), 0, sizeof(struct udb_radnode_d)); /* this creates the array lookup structure for n */ if(!udb_radnode_array_space(udb, &n, k[0], len-1)) { udb_radnode_delete(udb, &add); udb_ptr_free_space(&n, udb, sizeof(struct udb_radnode_d)); return 0; /* alloc failure */ } udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); RADNODE(&add)->pidx = 0; udb_rptr_set_ptr(&lookup(&n)->array[0].node, udb, &add); if(len > 1) { udb_radsel_prefix_remainder(1, k, len, lookup_string(&n, 0), &lookup(&n)->array[0].len); } udb_rptr_set_ptr(&RADTREE(rt)->root, udb, &n); } } else if(pos == len) { /* found an exact match */ if(RADNODE(&n)->elem.data) { /* already exists, failure */ udb_radnode_delete(udb, &add); udb_ptr_unlink(&n, udb); return 0; } udb_rptr_set_ptr(&RADNODE(&n)->elem, udb, elem); udb_radnode_delete(udb, &add); udb_ptr_set_ptr(&add, udb, &n); } else { /* n is a node which can accomodate */ uint8_t byte; assert(pos < len); byte = k[pos]; /* see if it falls outside of array */ if(byte < RADNODE(&n)->offset || byte-RADNODE(&n)->offset >= lookup(&n)->len) { /* make space in the array for it; adjusts offset */ if(!udb_radnode_array_space(udb, &n, byte, len-(pos+1))) { udb_radnode_delete(udb, &add); udb_ptr_unlink(&n, udb); return 0; } assert(byte>=RADNODE(&n)->offset && byte-RADNODE(&n)-> offsetlen); byte -= RADNODE(&n)->offset; /* see if more prefix needs to be split off */ if(pos+1 < len) { udb_radsel_str_create(lookup_string(&n, byte), &lookup(&n)->array[byte].len, k, pos+1, len); } /* insert the new node in the new bucket */ udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); RADNODE(&add)->pidx = byte; udb_rptr_set_ptr(&lookup(&n)->array[byte].node, udb, &add); /* so a bucket exists and byte falls in it */ } else if(lookup(&n)->array[byte - RADNODE(&n)->offset] .node.data == 0) { /* use existing bucket */ byte -= RADNODE(&n)->offset; if(pos+1 < len) { /* make space and split off more prefix */ if(!udb_radnode_str_space(udb, &n, len-(pos+1))) { udb_radnode_delete(udb, &add); udb_ptr_unlink(&n, udb); return 0; } udb_radsel_str_create(lookup_string(&n, byte), &lookup(&n)->array[byte].len, k, pos+1, len); } /* insert the new node in the new bucket */ udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); RADNODE(&add)->pidx = byte; udb_rptr_set_ptr(&lookup(&n)->array[byte].node, udb, &add); } else { /* use bucket but it has a shared prefix, * split that out and create a new intermediate * node to split out between the two. * One of the two might exactmatch the new * intermediate node */ if(!udb_radsel_split(udb, &n, byte-RADNODE(&n)->offset, k, pos+1, len, &add)) { udb_radnode_delete(udb, &add); udb_ptr_unlink(&n, udb); return 0; } } } RADTREE(rt)->count ++; ret = add.data; udb_ptr_init(result, udb); udb_ptr_set_ptr(result, udb, &add); udb_ptr_unlink(&add, udb); udb_ptr_unlink(&n, udb); return ret; } /** Cleanup node with one child, it is removed and joined into parent[x] str */ static int udb_radnode_cleanup_onechild(udb_base* udb, udb_ptr* n) { udb_ptr par, child; uint8_t pidx = RADNODE(n)->pidx; radstrlen_type joinlen; udb_ptr_new(&par, udb, &RADNODE(n)->parent); udb_ptr_new(&child, udb, &lookup(n)->array[0].node); /* node had one child, merge them into the parent. */ /* keep the child node, so its pointers stay valid. */ /* at parent, append child->str to array str */ assert(pidx < lookup(&par)->len); joinlen = lookup_len(&par, pidx) + lookup_len(n, 0) + 1; /* make stringspace for the joined string */ if(!udb_radnode_str_space(udb, &par, joinlen)) { /* cleanup failed due to out of memory */ /* the tree is inefficient, with node n still existing */ udb_ptr_unlink(&par, udb); udb_ptr_unlink(&child, udb); udb_ptr_zero(n, udb); return 0; } /* the string(par, pidx) is already there */ /* the array lookup is gone, put its character in the lookup string*/ lookup_string(&par, pidx)[lookup_len(&par, pidx)] = RADNODE(&child)->pidx + RADNODE(n)->offset; memmove(lookup_string(&par, pidx)+lookup_len(&par, pidx)+1, lookup_string(n, 0), lookup_len(n, 0)); lookup(&par)->array[pidx].len = joinlen; /* and set the node to our child. */ udb_rptr_set_ptr(&lookup(&par)->array[pidx].node, udb, &child); udb_rptr_set_ptr(&RADNODE(&child)->parent, udb, &par); RADNODE(&child)->pidx = pidx; /* we are unlinked, delete our node */ udb_radnode_delete(udb, n); udb_ptr_unlink(&par, udb); udb_ptr_unlink(&child, udb); udb_ptr_zero(n, udb); return 1; } /** reduce the size of radarray, does a malloc */ static int udb_radarray_reduce(udb_base* udb, udb_ptr* n, uint16_t cap, udb_radstrlen_type strcap) { udb_ptr a; unsigned i; assert(lookup(n)->len <= cap); assert(cap <= lookup(n)->capacity); assert(strcap <= lookup(n)->str_cap); if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, size_of_lookup_needed(cap, strcap))) return 0; memset(RADARRAY(&a), 0, size_of_lookup_needed(cap, strcap)); memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); RADARRAY(&a)->capacity = cap; RADARRAY(&a)->str_cap = strcap; for(i=0; ilen; i++) { udb_rel_ptr_init(&RADARRAY(&a)->array[i].node); udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, &lookup(n)->array[i].node); RADARRAY(&a)->array[i].len = lookup_len(n, i); memmove(((uint8_t*)(&RADARRAY(&a)->array[cap]))+i*strcap, lookup_string(n, i), lookup_len(n, i)); } udb_radarray_zero_ptrs(udb, n); udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); udb_ptr_unlink(&a, udb); return 1; } /** find the max stringlength in the array */ static udb_radstrlen_type udb_radarray_max_len(udb_ptr* n) { unsigned i; udb_radstrlen_type maxlen = 0; for(i=0; ilen; i++) { if(lookup(n)->array[i].node.data && lookup(n)->array[i].len > maxlen) maxlen = lookup(n)->array[i].len; } return maxlen; } /** see if radarray can be reduced (by a factor of two) */ static int udb_radarray_reduce_if_needed(udb_base* udb, udb_ptr* n) { udb_radstrlen_type maxlen = udb_radarray_max_len(n); if((lookup(n)->len <= lookup(n)->capacity/2 || lookup(n)->len == 0 || maxlen <= lookup(n)->str_cap/2 || maxlen == 0) && (lookup(n)->len != lookup(n)->capacity || lookup(n)->str_cap != maxlen)) return udb_radarray_reduce(udb, n, lookup(n)->len, maxlen); return 1; } static int udb_radnode_array_clean_all(udb_base* udb, udb_ptr* n) { RADNODE(n)->offset = 0; lookup(n)->len = 0; /* reallocate lookup to a smaller capacity structure */ return udb_radarray_reduce(udb, n, 0, 0); } /** remove NULL nodes from front of array */ static int udb_radnode_array_clean_front(udb_base* udb, udb_ptr* n) { /* move them up and adjust offset */ unsigned idx, shuf = 0; /* remove until a nonNULL entry */ while(shuf < lookup(n)->len && lookup(n)->array[shuf].node.data == 0) shuf++; if(shuf == 0) return 1; if(shuf == lookup(n)->len) { /* the array is empty, the tree is inefficient */ return udb_radnode_array_clean_all(udb, n); } assert(shuf < lookup(n)->len); assert((int)shuf <= 255-(int)RADNODE(n)->offset); /* move them */ for(idx=0; idxlen-shuf; idx++) { udb_rptr_set_rptr(&lookup(n)->array[idx].node, udb, &lookup(n)->array[shuf+idx].node); lookup(n)->array[idx].len = lookup_len(n, shuf+idx); memmove(lookup_string(n, idx), lookup_string(n, shuf+idx), lookup(n)->array[idx].len); } /* zero the to-be-unused entries */ for(idx=lookup(n)->len-shuf; idxlen; idx++) { udb_rptr_zero(&lookup(n)->array[idx].node, udb); memset(lookup_string(n, idx), 0, lookup(n)->array[idx].len); lookup(n)->array[idx].len = 0; } RADNODE(n)->offset += shuf; lookup(n)->len -= shuf; for(idx=0; idxlen; idx++) if(lookup(n)->array[idx].node.data) lookup_node(n, idx)->pidx = idx; /* see if capacity has to shrink */ return udb_radarray_reduce_if_needed(udb, n); } /** remove NULL nodes from end of array */ static int udb_radnode_array_clean_end(udb_base* udb, udb_ptr* n) { /* shorten it */ unsigned shuf = 0; /* remove until a nonNULL entry */ /* remove until a nonNULL entry */ while(shuf < lookup(n)->len && lookup(n)->array[lookup(n)->len-1-shuf] .node.data == 0) shuf++; if(shuf == 0) return 1; if(shuf == lookup(n)->len) { /* the array is empty, the tree is inefficient */ return udb_radnode_array_clean_all(udb, n); } assert(shuf < lookup(n)->len); lookup(n)->len -= shuf; /* array elements can stay where they are */ /* see if capacity has to shrink */ return udb_radarray_reduce_if_needed(udb, n); } /** clean up radnode leaf, where we know it has a parent */ static int udb_radnode_cleanup_leaf(udb_base* udb, udb_ptr* n, udb_ptr* par) { uint8_t pidx; /* node was a leaf */ /* delete leaf node, but store parent+idx */ pidx = RADNODE(n)->pidx; assert(pidx < lookup(par)->len); /** set parent ptr to this node to NULL before deleting the node, * because otherwise ptrlinks fail */ udb_rptr_zero(&lookup(par)->array[pidx].node, udb); udb_radnode_delete(udb, n); /* set parent+idx entry to NULL str and node.*/ lookup(par)->array[pidx].len = 0; /* see if par offset or len must be adjusted */ if(lookup(par)->len == 1) { /* removed final element from array */ if(!udb_radnode_array_clean_all(udb, par)) return 0; } else if(pidx == 0) { /* removed first element from array */ if(!udb_radnode_array_clean_front(udb, par)) return 0; } else if(pidx == lookup(par)->len-1) { /* removed last element from array */ if(!udb_radnode_array_clean_end(udb, par)) return 0; } return 1; } /** * Cleanup a radix node that was made smaller, see if it can * be merged with others. * @param udb: the udb * @param rt: tree to remove root if needed. * @param n: node to cleanup * @return false on alloc failure. */ static int udb_radnode_cleanup(udb_base* udb, udb_ptr* rt, udb_ptr* n) { while(!udb_ptr_is_null(n)) { if(RADNODE(n)->elem.data) { /* see if if needs to be reduced in stringsize */ if(!udb_radarray_reduce_if_needed(udb, n)) { udb_ptr_zero(n, udb); return 0; } /* cannot delete node with a data element */ udb_ptr_zero(n, udb); return 1; } else if(lookup(n)->len == 1 && RADNODE(n)->parent.data) { return udb_radnode_cleanup_onechild(udb, n); } else if(lookup(n)->len == 0) { udb_ptr par; if(!RADNODE(n)->parent.data) { /* root deleted */ udb_rptr_zero(&RADTREE(rt)->root, udb); udb_radnode_delete(udb, n); return 1; } udb_ptr_new(&par, udb, &RADNODE(n)->parent); /* remove and delete the leaf node */ if(!udb_radnode_cleanup_leaf(udb, n, &par)) { udb_ptr_unlink(&par, udb); udb_ptr_zero(n, udb); return 0; } /* see if parent can now be cleaned up */ udb_ptr_set_ptr(n, udb, &par); udb_ptr_unlink(&par, udb); } else { /* see if if needs to be reduced in stringsize */ if(!udb_radarray_reduce_if_needed(udb, n)) { udb_ptr_zero(n, udb); return 0; } /* node cannot be cleaned up */ udb_ptr_zero(n, udb); return 1; } } /* ENOTREACH */ return 1; } void udb_radix_delete(udb_base* udb, udb_ptr* rt, udb_ptr* n) { if(udb_ptr_is_null(n)) return; udb_rptr_zero(&RADNODE(n)->elem, udb); RADTREE(rt)->count --; if(!udb_radnode_cleanup(udb, rt, n)) { /* out of memory in cleanup. the elem ptr is NULL, but * the radix tree could be inefficient. */ } } udb_void udb_radix_search(udb_ptr* rt, uint8_t* k, udb_radstrlen_type len) { /* since we only perform reads, and no udb_mallocs or udb_frees * we know the pointers stay the same */ struct udb_radnode_d* n; udb_radstrlen_type pos = 0; uint8_t byte; void* base = *rt->base; n = (struct udb_radnode_d*)UDB_REL(base, RADTREE(rt)->root.data); #define NARRAY(n) ((struct udb_radarray_d*)UDB_REL(base, n->lookup.data)) #define NSTR(n, byte) (((uint8_t*)(&NARRAY(n)->array[NARRAY(n)->capacity]))+byte*NARRAY(n)->str_cap) while(n != *rt->base) { if(pos == len) return UDB_SYSTOREL(*rt->base, n); byte = k[pos]; if(byte < n->offset) return 0; byte -= n->offset; if(byte >= NARRAY(n)->len) return 0; pos++; if(NARRAY(n)->array[byte].len != 0) { /* must match additional string */ if(pos+NARRAY(n)->array[byte].len > len) return 0; /* no match */ if(memcmp(&k[pos], NSTR(n, byte), NARRAY(n)->array[byte].len) != 0) return 0; /* no match */ pos += NARRAY(n)->array[byte].len; } n = (struct udb_radnode_d*)UDB_REL(base, NARRAY(n)->array[byte].node.data); } return 0; } /** go to last elem-containing node in this subtree (excl self) */ static void udb_radnode_last_in_subtree(udb_base* udb, udb_ptr* n) { int idx; /* try last entry in array first */ for(idx=((int)lookup(n)->len)-1; idx >= 0; idx--) { if(lookup(n)->array[idx].node.data) { udb_ptr s; udb_ptr_init(&s, udb); udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); /* does it have entries in its subtrees? */ if(lookup(&s)->len > 0) { udb_radnode_last_in_subtree(udb, &s); if(!udb_ptr_is_null(&s)) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } } udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); /* no, does it have an entry itself? */ if(RADNODE(&s)->elem.data) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } udb_ptr_unlink(&s, udb); } } udb_ptr_zero(n, udb); } /** last in subtree, incl self */ static void udb_radnode_last_in_subtree_incl_self(udb_base* udb, udb_ptr* n) { udb_ptr self; udb_ptr_init(&self, udb); udb_ptr_set_ptr(&self, udb, n); udb_radnode_last_in_subtree(udb, n); if(!udb_ptr_is_null(n)) { udb_ptr_unlink(&self, udb); return; } if(RADNODE(&self)->elem.data) { udb_ptr_set_ptr(n, udb, &self); udb_ptr_unlink(&self, udb); return; } udb_ptr_zero(n, udb); udb_ptr_unlink(&self, udb); } /** return first elem-containing node in this subtree (excl self) */ static void udb_radnode_first_in_subtree(udb_base* udb, udb_ptr* n) { unsigned idx; /* try every subnode */ for(idx=0; idxlen; idx++) { if(lookup(n)->array[idx].node.data) { udb_ptr s; udb_ptr_init(&s, udb); udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); /* does it have elem itself? */ if(RADNODE(&s)->elem.data) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } /* try its subtrees */ udb_radnode_first_in_subtree(udb, &s); if(!udb_ptr_is_null(&s)) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } } } udb_ptr_zero(n, udb); } /** Find an entry in arrays from idx-1 to 0 */ static void udb_radnode_find_prev_from_idx(udb_base* udb, udb_ptr* n, unsigned from) { unsigned idx = from; while(idx > 0) { idx --; if(lookup(n)->array[idx].node.data) { udb_ptr_set_rptr(n, udb, &lookup(n)->array[idx].node); udb_radnode_last_in_subtree_incl_self(udb, n); if(!udb_ptr_is_null(n)) return; } } udb_ptr_zero(n, udb); } /** return self or a previous element */ static int udb_ret_self_or_prev(udb_base* udb, udb_ptr* n, udb_ptr* result) { if(RADNODE(n)->elem.data) { udb_ptr_set_ptr(result, udb, n); } else { udb_ptr_set_ptr(result, udb, n); udb_radix_prev(udb, result); } udb_ptr_unlink(n, udb); return 0; } int udb_radix_find_less_equal(udb_base* udb, udb_ptr* rt, uint8_t* k, udb_radstrlen_type len, udb_ptr* result) { udb_ptr n; udb_radstrlen_type pos = 0; uint8_t byte; int r; /* set result to NULL */ udb_ptr_init(result, udb); if(RADTREE(rt)->count == 0) { /* empty tree */ return 0; } udb_ptr_new(&n, udb, &RADTREE(rt)->root); while(pos < len) { byte = k[pos]; if(byte < RADNODE(&n)->offset) { /* so the previous is the element itself */ /* or something before this element */ return udb_ret_self_or_prev(udb, &n, result); } byte -= RADNODE(&n)->offset; if(byte >= lookup(&n)->len) { /* so, the previous is the last of array, or itself */ /* or something before this element */ udb_ptr_set_ptr(result, udb, &n); udb_radnode_last_in_subtree_incl_self(udb, result); if(udb_ptr_is_null(result)) { udb_ptr_set_ptr(result, udb, &n); udb_radix_prev(udb, result); } goto done_fail; } pos++; if(!lookup(&n)->array[byte].node.data) { /* no match */ /* Find an entry in arrays from byte-1 to 0 */ udb_ptr_set_ptr(result, udb, &n); udb_radnode_find_prev_from_idx(udb, result, byte); if(!udb_ptr_is_null(result)) goto done_fail; /* this entry or something before it */ udb_ptr_zero(result, udb); return udb_ret_self_or_prev(udb, &n, result); } if(lookup_len(&n, byte) != 0) { /* must match additional string */ if(pos+lookup_len(&n, byte) > len) { /* the additional string is longer than key*/ if( (r=memcmp(&k[pos], lookup_string(&n, byte), len-pos)) <= 0) { /* and the key is before this node */ udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radix_prev(udb, result); } else { /* the key is after the additional * string, thus everything in that * subtree is smaller. */ udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radnode_last_in_subtree_incl_self(udb, result); /* if somehow that is NULL, * then we have an inefficient tree: * byte+1 is larger than us, so find * something in byte-1 and before */ if(udb_ptr_is_null(result)) { udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radix_prev(udb, result); } } goto done_fail; /* no match */ } if( (r=memcmp(&k[pos], lookup_string(&n, byte), lookup_len(&n, byte))) < 0) { udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radix_prev(udb, result); goto done_fail; /* no match */ } else if(r > 0) { /* the key is larger than the additional * string, thus everything in that subtree * is smaller */ udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radnode_last_in_subtree_incl_self(udb, result); /* if we have an inefficient tree */ if(udb_ptr_is_null(result)) { udb_ptr_set_rptr(result, udb, &lookup(&n)->array[byte].node); udb_radix_prev(udb, result); } goto done_fail; /* no match */ } pos += lookup_len(&n, byte); } udb_ptr_set_rptr(&n, udb, &lookup(&n)->array[byte].node); } if(RADNODE(&n)->elem.data) { /* exact match */ udb_ptr_set_ptr(result, udb, &n); udb_ptr_unlink(&n, udb); return 1; } /* there is a node which is an exact match, but it has no element */ udb_ptr_set_ptr(result, udb, &n); udb_radix_prev(udb, result); done_fail: udb_ptr_unlink(&n, udb); return 0; } void udb_radix_first(udb_base* udb, udb_ptr* rt, udb_ptr* p) { udb_ptr_init(p, udb); if(!rt || udb_ptr_is_null(rt) || RADTREE(rt)->count == 0) return; udb_ptr_set_rptr(p, udb, &RADTREE(rt)->root); if(RADNODE(p)->elem.data) return; udb_radix_next(udb, p); } void udb_radix_last(udb_base* udb, udb_ptr* rt, udb_ptr* p) { udb_ptr_init(p, udb); if(!rt || udb_ptr_is_null(rt) || RADTREE(rt)->count == 0) return; udb_ptr_set_rptr(p, udb, &RADTREE(rt)->root); udb_radnode_last_in_subtree_incl_self(udb, p); } void udb_radix_next(udb_base* udb, udb_ptr* n) { udb_ptr s; udb_ptr_init(&s, udb); if(lookup(n)->len) { /* go down */ udb_ptr_set_ptr(&s, udb, n); udb_radnode_first_in_subtree(udb, &s); if(!udb_ptr_is_null(&s)) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } } /* go up - the parent->elem is not useful, because it is before us */ while(RADNODE(n)->parent.data) { unsigned idx = RADNODE(n)->pidx; udb_ptr_set_rptr(n, udb, &RADNODE(n)->parent); idx++; for(; idx < lookup(n)->len; idx++) { /* go down the next branch */ if(lookup(n)->array[idx].node.data) { udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); /* node itself */ if(RADNODE(&s)->elem.data) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } /* or subtree */ udb_radnode_first_in_subtree(udb, &s); if(!udb_ptr_is_null(&s)) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } } } } udb_ptr_unlink(&s, udb); udb_ptr_zero(n, udb); } void udb_radix_prev(udb_base* udb, udb_ptr* n) { /* must go up, since all array nodes are after this node */ while(RADNODE(n)->parent.data) { uint8_t idx = RADNODE(n)->pidx; udb_ptr s; udb_ptr_set_rptr(n, udb, &RADNODE(n)->parent); assert(lookup(n)->len > 0); /* since we are a child */ /* see if there are elements in previous branches there */ udb_ptr_init(&s, udb); udb_ptr_set_ptr(&s, udb, n); udb_radnode_find_prev_from_idx(udb, &s, idx); if(!udb_ptr_is_null(&s)) { udb_ptr_set_ptr(n, udb, &s); udb_ptr_unlink(&s, udb); return; } udb_ptr_unlink(&s, udb); /* the current node is before the array */ if(RADNODE(n)->elem.data) return; } udb_ptr_zero(n, udb); } udb_void udb_radname_insert(udb_base* udb, udb_ptr* rt, const uint8_t* dname, size_t dlen, udb_ptr* elem, udb_ptr* result) { uint8_t k[300]; radstrlen_type klen = (radstrlen_type)sizeof(k); radname_d2r(k, &klen, dname, dlen); return udb_radix_insert(udb, rt, k, klen, elem, result); } int udb_radname_search(udb_base* udb, udb_ptr* rt, const uint8_t* dname, size_t dlen, udb_ptr* result) { udb_void r; uint8_t k[300]; radstrlen_type klen = (radstrlen_type)sizeof(k); radname_d2r(k, &klen, dname, dlen); r = udb_radix_search(rt, k, klen); udb_ptr_init(result, udb); udb_ptr_set(result, udb, r); return (r != 0); } void udb_radix_tree_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct udb_radtree_d* p = (struct udb_radtree_d*)d; assert(s >= sizeof(struct udb_radtree_d)); (void)s; (*cb)(base, &p->root, arg); } void udb_radix_node_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct udb_radnode_d* p = (struct udb_radnode_d*)d; assert(s >= sizeof(struct udb_radnode_d)); (void)s; (*cb)(base, &p->elem, arg); (*cb)(base, &p->parent, arg); (*cb)(base, &p->lookup, arg); } void udb_radix_array_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg) { struct udb_radarray_d* p = (struct udb_radarray_d*)d; unsigned i; assert(s >= sizeof(struct udb_radarray_d)+ p->capacity*(sizeof(struct udb_radsel_d)+p->str_cap)); (void)s; for(i=0; ilen; i++) { (*cb)(base, &p->array[i].node, arg); } } nsd-4.1.26/lookup3.h0000664000175000017500000000517712275161154013611 0ustar wouterwouter/* * util/storage/lookup3.h - header file for hashing functions. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains header definitions for the hash functions we use. * The hash functions are public domain (see lookup3.c). */ #ifndef UTIL_STORAGE_LOOKUP3_H #define UTIL_STORAGE_LOOKUP3_H /** * Hash key made of 4byte chunks. * @param k: the key, an array of uint32_t values * @param length: the length of the key, in uint32_ts * @param initval: the previous hash, or an arbitrary value * @return: hash value. */ uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval); /** * Hash key data. * @param k: the key, array of uint8_t * @param length: the length of the key, in uint8_ts * @param initval: the previous hash, or an arbitrary value * @return: hash value. */ uint32_t hashlittle(const void *k, size_t length, uint32_t initval); /** * Set the randomisation initial value, set this before threads start, * and before hashing stuff (because it changes subsequent results). * @param v: value */ void hash_set_raninit(uint32_t v); #endif /* UTIL_STORAGE_LOOKUP3_H */ nsd-4.1.26/configyyrename.h0000664000175000017500000000652012533327210015217 0ustar wouterwouter/* * configyyrename.h -- renames for config file yy values to avoid conflicts. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef CONFIGYYRENAME_H #define CONFIGYYRENAME_H #include "config.h" /* defines to change symbols so that no yacc/lex symbols clash */ #define yymaxdepth c_maxdepth #define yyparse c_parse #define yylex c_lex #define yyerror c_error #define yylval c_lval #define yychar c_char #define yydebug c_debug #define yypact c_pact #define yyr1 c_r1 #define yyr2 c_r2 #define yydef c_def #define yychk c_chk #define yypgo c_pgo #define yyact c_act #define yyexca c_exca #define yyerrflag c_errflag #define yynerrs c_nerrs #define yyps c_ps #define yypv c_pv #define yys c_s #define yyss c_ss #define yy_yys c_yys #define yystate c_state #define yytmp c_tmp #define yyv c_v #define yy_yyv c_yyv #define yyval c_val #define yylloc c_lloc #define yyreds c_reds #define yytoks c_toks #define yylhs c_yylhs #define yylen c_yylen #define yydefred c_yydefred #define yydgoto c_yydgoto #define yysindex c_yysindex #define yyrindex c_yyrindex #define yygindex c_yygindex #define yytable c_yytable #define yycheck c_yycheck #define yyname c_yyname #define yyrule c_yyrule #define yyin c_in #define yyout c_out #define yywrap c_wrap #define yy_load_buffer_state c_load_buffer_state #define yy_switch_to_buffer c_switch_to_buffer #define yy_flush_buffer c_flush_buffer #define yy_init_buffer c_init_buffer #define yy_scan_buffer c_scan_buffer #define yy_scan_bytes c_scan_bytes #define yy_scan_string c_scan_string #define yy_create_buffer c_create_buffer #define yyrestart c_restart #define yy_delete_buffer c_delete_buffer #define yypop_buffer_state c_pop_buffer_state #define yypush_buffer_state c_push_buffer_state #define yyunput c_unput #define yyset_in c_set_in #define yyget_in c_get_in #define yyset_out c_set_out #define yyget_out c_get_out #define yyget_lineno c_get_lineno #define yyset_lineno c_set_lineno #define yyset_debug c_set_debug #define yyget_debug c_get_debug #define yy_flex_debug c_flex_debug #define yylex_destroy c_lex_destroy #define yyfree c_free #define yyrealloc c_realloc #define yyalloc c_alloc #define yymalloc c_malloc #define yyget_leng c_get_leng #define yylineno c_lineno #define yyget_text c_get_text #define yyvsp c_vsp #define yyvs c_vs #define yytext c_text #define yyleng c_leng #define yy_meta c__meta #define yy_start c__start #define yy_nxt c__nxt #define yy_n_chars c__n_chars #define yy_more_flag c__more_flag #define yy_more_len c__more_len #define yy_try_NUL_trans c__try_NUL_trans #define yy_last_accepting_cpos c__last_accepting_cpos #define yy_last_accepting_state c__last_accepting_state #define yy_init c__init #define yy_base c__base #define yy_accept c__accept #define yy_c_buf_p c__c_buf_p #define yy_chk c__chk #ifndef LEX_DEFINES_YY_CURRENT_BUFFER # define yy_current_buffer c__current_buffer #endif #define yy_def c__def #define yy_did_buffer_switch_on_eof c__did_buffer_switch_on_eof #define yy_ec c__ec #define yy_fatal_error c__fatal_error #define yy_flex_alloc c__flex_alloc #define yy_flex_free c__flex_free #define yy_flex_realloc c__flex_realloc #define yy_get_next_buffer c__get_next_buffer #define yy_get_previous_state c__get_previous_state #define yy_hold_char c__hold_char #endif /* CONFIGYYRENAME_H */ nsd-4.1.26/configparser.h0000664000175000017500000001674213401455025014672 0ustar wouterwouter/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_YY_CONFIGPARSER_H_INCLUDED # define YY_YY_CONFIGPARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { SPACE = 258, LETTER = 259, NEWLINE = 260, COMMENT = 261, COLON = 262, ANY = 263, ZONESTR = 264, STRING = 265, VAR_SERVER = 266, VAR_NAME = 267, VAR_IP_ADDRESS = 268, VAR_IP_TRANSPARENT = 269, VAR_DEBUG_MODE = 270, VAR_IP4_ONLY = 271, VAR_IP6_ONLY = 272, VAR_DATABASE = 273, VAR_IDENTITY = 274, VAR_NSID = 275, VAR_LOGFILE = 276, VAR_SERVER_COUNT = 277, VAR_TCP_COUNT = 278, VAR_PIDFILE = 279, VAR_PORT = 280, VAR_STATISTICS = 281, VAR_CHROOT = 282, VAR_USERNAME = 283, VAR_ZONESDIR = 284, VAR_XFRDFILE = 285, VAR_DIFFFILE = 286, VAR_XFRD_RELOAD_TIMEOUT = 287, VAR_TCP_QUERY_COUNT = 288, VAR_TCP_TIMEOUT = 289, VAR_IPV4_EDNS_SIZE = 290, VAR_IPV6_EDNS_SIZE = 291, VAR_DO_IP4 = 292, VAR_DO_IP6 = 293, VAR_TCP_MSS = 294, VAR_OUTGOING_TCP_MSS = 295, VAR_IP_FREEBIND = 296, VAR_ZONEFILE = 297, VAR_ZONE = 298, VAR_ALLOW_NOTIFY = 299, VAR_REQUEST_XFR = 300, VAR_NOTIFY = 301, VAR_PROVIDE_XFR = 302, VAR_SIZE_LIMIT_XFR = 303, VAR_NOTIFY_RETRY = 304, VAR_OUTGOING_INTERFACE = 305, VAR_ALLOW_AXFR_FALLBACK = 306, VAR_KEY = 307, VAR_ALGORITHM = 308, VAR_SECRET = 309, VAR_AXFR = 310, VAR_UDP = 311, VAR_VERBOSITY = 312, VAR_HIDE_VERSION = 313, VAR_PATTERN = 314, VAR_INCLUDEPATTERN = 315, VAR_ZONELISTFILE = 316, VAR_REMOTE_CONTROL = 317, VAR_CONTROL_ENABLE = 318, VAR_CONTROL_INTERFACE = 319, VAR_CONTROL_PORT = 320, VAR_SERVER_KEY_FILE = 321, VAR_SERVER_CERT_FILE = 322, VAR_CONTROL_KEY_FILE = 323, VAR_CONTROL_CERT_FILE = 324, VAR_XFRDIR = 325, VAR_RRL_SIZE = 326, VAR_RRL_RATELIMIT = 327, VAR_RRL_SLIP = 328, VAR_RRL_IPV4_PREFIX_LENGTH = 329, VAR_RRL_IPV6_PREFIX_LENGTH = 330, VAR_RRL_WHITELIST_RATELIMIT = 331, VAR_RRL_WHITELIST = 332, VAR_ZONEFILES_CHECK = 333, VAR_ZONEFILES_WRITE = 334, VAR_LOG_TIME_ASCII = 335, VAR_ROUND_ROBIN = 336, VAR_ZONESTATS = 337, VAR_REUSEPORT = 338, VAR_VERSION = 339, VAR_MAX_REFRESH_TIME = 340, VAR_MIN_REFRESH_TIME = 341, VAR_MAX_RETRY_TIME = 342, VAR_MIN_RETRY_TIME = 343, VAR_MULTI_MASTER_CHECK = 344, VAR_MINIMAL_RESPONSES = 345, VAR_REFUSE_ANY = 346, VAR_USE_SYSTEMD = 347, VAR_DNSTAP = 348, VAR_DNSTAP_ENABLE = 349, VAR_DNSTAP_SOCKET_PATH = 350, VAR_DNSTAP_SEND_IDENTITY = 351, VAR_DNSTAP_SEND_VERSION = 352, VAR_DNSTAP_IDENTITY = 353, VAR_DNSTAP_VERSION = 354, VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES = 355, VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES = 356 }; #endif /* Tokens. */ #define SPACE 258 #define LETTER 259 #define NEWLINE 260 #define COMMENT 261 #define COLON 262 #define ANY 263 #define ZONESTR 264 #define STRING 265 #define VAR_SERVER 266 #define VAR_NAME 267 #define VAR_IP_ADDRESS 268 #define VAR_IP_TRANSPARENT 269 #define VAR_DEBUG_MODE 270 #define VAR_IP4_ONLY 271 #define VAR_IP6_ONLY 272 #define VAR_DATABASE 273 #define VAR_IDENTITY 274 #define VAR_NSID 275 #define VAR_LOGFILE 276 #define VAR_SERVER_COUNT 277 #define VAR_TCP_COUNT 278 #define VAR_PIDFILE 279 #define VAR_PORT 280 #define VAR_STATISTICS 281 #define VAR_CHROOT 282 #define VAR_USERNAME 283 #define VAR_ZONESDIR 284 #define VAR_XFRDFILE 285 #define VAR_DIFFFILE 286 #define VAR_XFRD_RELOAD_TIMEOUT 287 #define VAR_TCP_QUERY_COUNT 288 #define VAR_TCP_TIMEOUT 289 #define VAR_IPV4_EDNS_SIZE 290 #define VAR_IPV6_EDNS_SIZE 291 #define VAR_DO_IP4 292 #define VAR_DO_IP6 293 #define VAR_TCP_MSS 294 #define VAR_OUTGOING_TCP_MSS 295 #define VAR_IP_FREEBIND 296 #define VAR_ZONEFILE 297 #define VAR_ZONE 298 #define VAR_ALLOW_NOTIFY 299 #define VAR_REQUEST_XFR 300 #define VAR_NOTIFY 301 #define VAR_PROVIDE_XFR 302 #define VAR_SIZE_LIMIT_XFR 303 #define VAR_NOTIFY_RETRY 304 #define VAR_OUTGOING_INTERFACE 305 #define VAR_ALLOW_AXFR_FALLBACK 306 #define VAR_KEY 307 #define VAR_ALGORITHM 308 #define VAR_SECRET 309 #define VAR_AXFR 310 #define VAR_UDP 311 #define VAR_VERBOSITY 312 #define VAR_HIDE_VERSION 313 #define VAR_PATTERN 314 #define VAR_INCLUDEPATTERN 315 #define VAR_ZONELISTFILE 316 #define VAR_REMOTE_CONTROL 317 #define VAR_CONTROL_ENABLE 318 #define VAR_CONTROL_INTERFACE 319 #define VAR_CONTROL_PORT 320 #define VAR_SERVER_KEY_FILE 321 #define VAR_SERVER_CERT_FILE 322 #define VAR_CONTROL_KEY_FILE 323 #define VAR_CONTROL_CERT_FILE 324 #define VAR_XFRDIR 325 #define VAR_RRL_SIZE 326 #define VAR_RRL_RATELIMIT 327 #define VAR_RRL_SLIP 328 #define VAR_RRL_IPV4_PREFIX_LENGTH 329 #define VAR_RRL_IPV6_PREFIX_LENGTH 330 #define VAR_RRL_WHITELIST_RATELIMIT 331 #define VAR_RRL_WHITELIST 332 #define VAR_ZONEFILES_CHECK 333 #define VAR_ZONEFILES_WRITE 334 #define VAR_LOG_TIME_ASCII 335 #define VAR_ROUND_ROBIN 336 #define VAR_ZONESTATS 337 #define VAR_REUSEPORT 338 #define VAR_VERSION 339 #define VAR_MAX_REFRESH_TIME 340 #define VAR_MIN_REFRESH_TIME 341 #define VAR_MAX_RETRY_TIME 342 #define VAR_MIN_RETRY_TIME 343 #define VAR_MULTI_MASTER_CHECK 344 #define VAR_MINIMAL_RESPONSES 345 #define VAR_REFUSE_ANY 346 #define VAR_USE_SYSTEMD 347 #define VAR_DNSTAP 348 #define VAR_DNSTAP_ENABLE 349 #define VAR_DNSTAP_SOCKET_PATH 350 #define VAR_DNSTAP_SEND_IDENTITY 351 #define VAR_DNSTAP_SEND_VERSION 352 #define VAR_DNSTAP_IDENTITY 353 #define VAR_DNSTAP_VERSION 354 #define VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES 355 #define VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES 356 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 42 "configparser.y" /* yacc.c:1909 */ char* str; #line 260 "configparser.h" /* yacc.c:1909 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_CONFIGPARSER_H_INCLUDED */ nsd-4.1.26/tsig.h0000664000175000017500000001650712526326016013161 0ustar wouterwouter/* * tsig.h -- TSIG definitions (RFC 2845). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _TSIG_H_ #define _TSIG_H_ #include #include #include #include "buffer.h" #include "dname.h" #define TSIG_ERROR_NOERROR 0 #define TSIG_ERROR_BADSIG 16 #define TSIG_ERROR_BADKEY 17 #define TSIG_ERROR_BADTIME 18 typedef struct tsig_algorithm tsig_algorithm_type; typedef struct tsig_key tsig_key_type; typedef struct tsig_record tsig_record_type; enum tsig_status { TSIG_NOT_PRESENT, TSIG_OK, TSIG_ERROR }; typedef enum tsig_status tsig_status_type; struct tsig_lookup_struct_table { uint8_t id; const char* short_name; }; typedef struct tsig_lookup_struct_table tsig_lookup_algorithm_table; /* * A TSIG HMAC algorithm, such as hmac-md5. */ struct tsig_algorithm { /* * Short name of the algorithm, such as "hmac-md5". */ const char *short_name; /* * Full wireformat name of the algorithm, such as * "hmac-md5.sig-alg.reg.int." */ const dname_type *wireformat_name; /* * The maximum size of a digest generated by this algorithm. */ size_t maximum_digest_size; /* * Algorithm implementation specific data. */ const void *data; /* * Create a new HMAC context. */ void *(*hmac_create_context)(region_type *region); /* * Initialize an HMAC context with the specified algorithm and * key. */ void (*hmac_init_context)(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key); /* * Update the HMAC context with the specified data. */ void (*hmac_update)(void *context, const void *data, size_t size); /* * Generate the final digest. DIGEST points to a buffer of at * least maximum_digest_size bytes. */ void (*hmac_final)(void *context, uint8_t *digest, size_t *size); }; /* * A TSIG key used to sign and verify packets. */ struct tsig_key { const dname_type *name; size_t size; uint8_t *data; }; struct tsig_record { tsig_status_type status; size_t position; size_t response_count; size_t updates_since_last_prepare; void *context; tsig_algorithm_type *algorithm; tsig_key_type *key; size_t prior_mac_size; uint8_t *prior_mac_data; /* TSIG RR data is allocated in the rr_region. */ region_type *rr_region; region_type *context_region; const dname_type *key_name; const dname_type *algorithm_name; uint16_t signed_time_high; uint32_t signed_time_low; uint16_t signed_time_fudge; uint16_t mac_size; uint8_t *mac_data; uint16_t original_query_id; uint16_t error_code; uint16_t other_size; uint8_t *other_data; }; /* * Initialize the TSIG module (including TSIG implementation modules * such as tsig-openssl). */ int tsig_init(region_type *region); /* * Add the specified key to the TSIG key table. */ void tsig_add_key(tsig_key_type *key); void tsig_del_key(tsig_key_type *key); /* * Add the specified algorithm to the TSIG algorithm table. */ void tsig_add_algorithm(tsig_algorithm_type *algorithm); /* * Find an HMAC algorithm based on its short name. */ tsig_algorithm_type *tsig_get_algorithm_by_name(const char *name); /* * Return a descriptive error message based on the TSIG error code. */ const char *tsig_error(int error_code); /* * Create the tsig record internal structure. Allocs it. * Call init_record afterwards before doing more with it. * * The region is used to attach a cleanup function that destroys the tsig. */ void tsig_create_record(tsig_record_type* tsig, region_type* region); /* * Like tsig_create_record, with custom region settings. * The size params are used to customise the rr_region and context_region. * If region is NULL, no cleanup is attached to it. */ void tsig_create_record_custom(tsig_record_type* tsig, region_type* region, size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size); /* * Destroy tsig record internals (the main ptr is user alloced). * if region is nonNULL, removes cleanup. */ void tsig_delete_record(tsig_record_type* tsig, region_type* region); /* * Call this before starting to analyze or signing a sequence of * packets. * * ALGORITHM and KEY are optional and are only needed if you want to * sign the initial query. Otherwise the key and algorithm are looked * up in the algorithm and key table when a received TSIG RR is * processed. */ void tsig_init_record(tsig_record_type *data, tsig_algorithm_type *algorithm, tsig_key_type *key); /* * Validate the TSIG RR key and algorithm from the TSIG RR. Otherwise * update the TSIG error code. The MAC itself is not validated. * * Returns non-zero if the key and algorithm could be validated. */ int tsig_from_query(tsig_record_type *tsig); /* * Prepare TSIG for signing of a query. This initializes TSIG with * the algorithm and key stored in the TSIG record. */ void tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id); /* * Prepare TSIG for performing an HMAC calculation. If the TSIG * contains a prior HMAC it is inserted first into the hash * calculation. */ void tsig_prepare(tsig_record_type *tsig); /* * Add the first LENGTH octets of PACKET to the TSIG hash, replacing * the PACKET's id with the original query id from TSIG. If the query * is a response the TSIG response count is incremented. */ void tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length); /* * Finalize the TSIG record by hashing the TSIG data. If the TSIG * response count is greater than 1 only the timers are hashed. * Signed time is set to the current time. The TSIG record can be * added to a packet using tsig_append_rr(). * * The calculated MAC is also stored as the prior MAC, so it can be * used as a running MAC. */ void tsig_sign(tsig_record_type *tsig); /* * Verify the calculated MAC against the MAC in the TSIG RR. * * The calculated MAC is also stored as the prior MAC, so it can be * used as a running MAC. */ int tsig_verify(tsig_record_type *tsig); /* * Find the TSIG RR in QUERY and parse it if present. Store the * parsed results in TSIG. * * Returns non-zero if no parsing error occurred, use the tsig->status * field to find out if the TSIG record was present. */ int tsig_find_rr(tsig_record_type *tsig, buffer_type *packet); /* * Call this to analyze the TSIG RR starting at the current location * of PACKET. On success true is returned and the results are stored * in TSIG. * * Returns non-zero if no parsing error occurred, use the tsig->status * field to find out if the TSIG record was present. */ int tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet); /* * Append the TSIG record to the response PACKET. */ void tsig_append_rr(tsig_record_type *tsig, buffer_type *packet); /* * The amount of space to reserve in the response for the TSIG data * (if required). */ size_t tsig_reserved_space(tsig_record_type *tsig); /* * status or error_code must already be in error. * prepares content for error packet. */ void tsig_error_reply(tsig_record_type *tsig); /* * compare tsig algorithm names case insensitive. */ int tsig_strlowercmp(const char* str1, const char* str2); /* * cleanup tsig openssl stuff. */ void tsig_finalize(void); #endif /* _TSIG_H_ */ nsd-4.1.26/edns.h0000664000175000017500000000313212764236564013146 0ustar wouterwouter/* * edns.h -- EDNS definitions (RFC 2671). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _EDNS_H_ #define _EDNS_H_ #include "buffer.h" struct nsd; struct query; #define OPT_LEN 9U /* Length of the NSD EDNS response record minus 2 */ #define OPT_RDATA 2 /* holds the rdata length comes after OPT_LEN */ #define OPT_HDR 4U /* NSID opt header length */ #define NSID_CODE 3 /* nsid option code */ #define DNSSEC_OK_MASK 0x8000U /* do bit mask */ struct edns_data { char ok[OPT_LEN]; char error[OPT_LEN]; char rdata_none[OPT_RDATA]; char rdata_nsid[OPT_RDATA]; char nsid[OPT_HDR]; }; typedef struct edns_data edns_data_type; enum edns_status { EDNS_NOT_PRESENT, EDNS_OK, /* EDNS states may be extended in the future */ EDNS_ERROR }; typedef enum edns_status edns_status_type; struct edns_record { edns_status_type status; size_t position; size_t maxlen; size_t opt_reserved_space; int dnssec_ok; int nsid; }; typedef struct edns_record edns_record_type; void edns_init_data(edns_data_type *data, uint16_t max_length); void edns_init_record(edns_record_type *data); int edns_parse_record(edns_record_type *data, buffer_type *packet, struct query* q, struct nsd* nsd); /* * The amount of space to reserve in the response for the EDNS data * (if required). */ size_t edns_reserved_space(edns_record_type *data); void edns_init_nsid(edns_data_type *data, uint16_t nsid_len); #endif /* _EDNS_H_ */ nsd-4.1.26/iterated_hash.c0000664000175000017500000000167711563223507015015 0ustar wouterwouter/* * iterated_hash.c -- nsec3 hash calculation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * With thanks to Ben Laurie. */ #include "config.h" #ifdef NSEC3 #include #include #include #include "iterated_hash.h" int iterated_hash(unsigned char out[SHA_DIGEST_LENGTH], const unsigned char *salt, int saltlength, const unsigned char *in, int inlength, int iterations) { #if defined(NSEC3) && defined(HAVE_SSL) SHA_CTX ctx; int n; assert(in && inlength > 0 && iterations >= 0); for(n=0 ; n <= iterations ; ++n) { SHA1_Init(&ctx); SHA1_Update(&ctx, in, inlength); if(saltlength > 0) SHA1_Update(&ctx, salt, saltlength); SHA1_Final(out, &ctx); in=out; inlength=SHA_DIGEST_LENGTH; } return SHA_DIGEST_LENGTH; #else (void)out; (void)salt; (void)saltlength; (void)in; (void)inlength; (void)iterations; return 0; #endif } #endif /* NSEC3 */ nsd-4.1.26/nsd.conf.5.in0000664000175000017500000007672213401455025014246 0ustar wouterwouter.TH "nsd.conf" "5" "Dec 4, 2018" "NLnet Labs" "nsd 4.1.26" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd.conf \- NSD configuration file .SH "SYNOPSIS" .B nsd.conf .SH "DESCRIPTION" .B Nsd.conf is used to configure nsd(8). The file format has attributes and values. Some attributes have attributes inside them. The notation is: attribute: value. .PP Comments start with # and last to the end of line. Empty lines are ignored as is whitespace at the beginning of a line. Quotes can be used, for names with spaces, eg. "file name.zone". .PP .B Nsd.conf specifies options for the nsd server, zone files, primaries and secondaries. .SH "EXAMPLE" An example of a short nsd.conf file is below. .LP # Example.com nsd.conf file .RS 0 # This is a comment. .RE .TP server: .RS 5 server-count: 1 # use this number of cpu cores .RE .RS 5 database: "" # or use "@dbfile@" .RE .RS 5 zonelistfile: "@zonelistfile@" .RE .RS 5 username: @user@ .RE .RS 5 logfile: "@logfile@" .RE .RS 5 pidfile: "@pidfile@" .RE .RS 5 xfrdfile: "@xfrdfile@" .RE .TP zone: .RS 5 name: example.com .RE .RS 5 zonefile: @configdir@/example.com.zone .RE .TP zone: .RS 5 # this server is master, 192.0.2.1 is the secondary. .RE .RS 5 name: masterzone.com .RE .RS 5 zonefile: @configdir@/masterzone.com.zone .RE .RS 5 notify: 192.0.2.1 NOKEY .RE .RS 5 provide-xfr: 192.0.2.1 NOKEY .RE .TP zone: .RS 5 # this server is secondary, 192.0.2.2 is master. .RE .RS 5 name: secondzone.com .RE .RS 5 zonefile: @configdir@/secondzone.com.zone .RE .RS 5 allow-notify: 192.0.2.2 NOKEY .RE .RS 5 request-xfr: 192.0.2.2 NOKEY .RE .LP Then, use kill \-HUP to reload changes from master zone files. And use kill \-TERM to stop the server. .SH "FILE FORMAT" There must be whitespace between keywords. Attribute keywords end with a colon ':'. An attribute is followed by its containing attributes, or a value. .P At the top level only .B server: and .B key: and .B pattern: and .B zone: are allowed. These are followed by their attributes or the start of a new .B server: or .B key: or .B pattern: or .B zone: clause. The .B zone: attribute is followed by zone options. The .B server: attribute is followed by global options for the .B NSD server. A .B key: attribute is used to define keys for authentication. The .B pattern: attribute is followed by the zone options for zones that use the pattern. .P Files can be included using the .B include: directive. It can appear anywhere, and takes a single filename as an argument. Processing continues as if the text from the included file was copied into the config file at that point. If a chroot is used an absolute filename is needed (with the chroot prepended), so that the include can be parsed before and after application of the chroot (and the knowledge of what that chroot is). You can use '*' to include a wildcard match of files, eg. "foo/nsd.d/*.conf". Also '?', '{}', '[]', and '~' work, see \fBglob\fR(7). If no files match the pattern, this is not an error. .SS "Server Options" .LP The global options (if not overridden from the NSD commandline) are taken from the .B server: clause. There may only be one .B server: clause. .TP .B ip\-address:\fR [@port] NSD will bind to the listed ip\-address. Can be give multiple times to bind multiple ip\-addresses. Optionally, a port number can be given. If none are given NSD listens to the wildcard interface. Same as commandline option .BR \-a. For servers with multiple IP addresses that can be used to send traffic to the internet, list them one by one, or the source address of replies could be wrong. This is because if the udp socket associates a source address of 0.0.0.0 then the kernel picks an ip-address with which to send to the internet, and it picks the wrong one. Typically needed for anycast instances. Use ip-transparent to be able to list addresses that turn on later (typical for certain load-balancing). .TP .B interface:\fR [@port] Same as ip\-address (for easy of compatibility with unbound.conf). .TP .B ip\-transparent:\fR Allows NSD to bind to non local addresses. This is useful to have NSD listen to IP addresses that are not (yet) added to the network interface, so that it can answer immediately when the address is added. Default is no. .TP .B ip\-freebind:\fR Set the IP_FREEBIND option to bind to nonlocal addresses and interfaces that are down. Similar to ip\-transparent. Default is no. .TP .B reuseport:\fR Use the SO_REUSEPORT socket option, and create file descriptors for every server in the server\-count. This improves performance of the network stack. Only really useful if you also configure a server\-count higher than 1 (such as, equal to the number of cpus). The default is no. It works on Linux, but does not work on FreeBSD, and likely does not work on other systems. .TP .B debug\-mode:\fR Turns on debugging mode for nsd, does not fork a daemon process. Default is no. Same as commandline option .BR \-d. If set to yes it does not fork and stays in the foreground, which can be helpful for commandline debugging, but is also used by certain server supervisor processes to ascertain that the server is running. .TP .B do\-ip4:\fR If yes, NSD listens to IPv4 connections. Default yes. .TP .B do\-ip6:\fR If yes, NSD listens to IPv6 connections. Default yes. .TP .B database:\fR By default .I '@dbfile@' is used. The specified file is used to store the compiled zone information. Same as commandline option .BR \-f. If set to "" then no database is used. This uses less memory but zone updates are not (immediately) spooled to disk. .TP .B zonelistfile:\fR By default .I @zonelistfile@ is used. The specified file is used to store the dynamically added list of zones. The list is written to by NSD to add and delete zones. It is a text file with a zone\-name and pattern\-name on each line. This file is used for the nsd\-control addzone and delzone commands. .TP .B identity:\fR Returns the specified identity when asked for CH TXT ID.SERVER. Default is the name as returned by gethostname(3). Same as commandline option .BR \-i . .TP .B version:\fR Returns the specified version string when asked for CH TXT version.server, and version.bind queries. Default is the compiled package version. See hide\-version to set the server to not respond to such queries. .TP .B nsid:\fR Add the specified nsid to the EDNS section of the answer when queried with an NSID EDNS enabled packet. As a sequence of hex characters or with ascii_ prefix and then an ascii string. Same as commandline option .BR \-I . .TP .B logfile:\fR Log messages to the logfile. The default is to log to stderr and syslog (with facility LOG_DAEMON). Same as commandline option .BR \-l . .TP .B server\-count:\fR Start this many NSD servers. Default is 1. Same as commandline option .BR \-N . .TP .B tcp\-count:\fR The maximum number of concurrent, active TCP connections by each server. Default is 100. Same as commandline option .BR \-n . .TP .B tcp\-query\-count:\fR The maximum number of queries served on a single TCP connection. Default is 0, meaning there is no maximum. .TP .B tcp\-timeout:\fR Overrides the default TCP timeout. This also affects zone transfers over TCP. .TP .B tcp-mss:\fR Maximum segment size (MSS) of TCP socket on which the server responds to queries. Value lower than common MSS on Ethernet (1220 for example) will address path MTU problem. Note that not all platform supports socket option to set MSS (TCP_MAXSEG). Default is system default MSS determined by interface MTU and negotiation between server and client. .TP .B outgoing\-tcp\-mss:\fR Maximum segment size (MSS) of TCP socket for outgoing XFR request to other namesevers. Value lower than common MSS on Ethernet (1220 for example) will address path MTU problem. Note that not all platform supports socket option to set MSS (TCP_MAXSEG). Default is system default MSS determined by interface MTU and negotiation between NSD and other servers. .TP .B ipv4\-edns\-size:\fR Preferred EDNS buffer size for IPv4. Default 4096. .TP .B ipv6\-edns\-size:\fR Preferred EDNS buffer size for IPv6. Default 4096. .TP .B pidfile:\fR Use the pid file instead of the platform specific default, usually .IR @pidfile@. Same as commandline option .BR \-P . .TP .B port:\fR Answer queries on the specified port. Default is 53. Same as commandline option .BR \-p . .TP .B statistics:\fR If not present no statistics are dumped. Statistics are produced every number seconds. Same as commandline option .BR \-s . .TP .B chroot:\fR NSD will chroot on startup to the specified directory. Note that if elsewhere in the configuration you specify an absolute pathname to a file inside the chroot, you have to prepend the \fBchroot\fR path. That way, you can switch the chroot option on and off without having to modify anything else in the configuration. Set the value to "" (the empty string) to disable the chroot. By default "\fI@chrootdir@\fR" is used. Same as commandline option .BR \-t . .TP .B username:\fR After binding the socket, drop user privileges and assume the username. Can be username, id or id.gid. Same as commandline option .BR \-u . .TP .B zonesdir:\fR Change the working directory to the specified directory before accessing zone files. Also, NSD will access \fBdatabase\fR, \fBzonelistfile\fR, \fBlogfile\fR, \fBpidfile\fR, \fBxfrdfile\fR, \fBxfrdir\fR, \fBserver-key-file\fR, \fBserver-cert-file\fR, \fBcontrol-key-file\fR and \fBcontrol-cert-file\fR relative to this directory. Set the value to "" (the empty string) to disable the change of working directory. By default "\fI@zonesdir@\fR" is used. .TP .B difffile:\fR Ignored, for compatibility with NSD3 config files. .TP .B xfrdfile:\fR The soa timeout and zone transfer daemon in NSD will save its state to this file. State is read back after a restart. The state file can be deleted without too much harm, but timestamps of zones will be gone. If it is configured as "", the state file is not used, all slave zones are checked for updates upon startup. For more details see the section on zone expiry behavior of NSD. Default is .IR @xfrdfile@ . .TP .B xfrdir:\fR The zone transfers are stored here before they are processed. A directory is created here that is removed when NSD exits. Default is .IR @xfrdir@ . .TP .B xfrd\-reload\-timeout:\fR If this value is \-1, xfrd will not trigger a reload after a zone transfer. If positive xfrd will trigger a reload after a zone transfer, then it will wait for the number of seconds before it will trigger a new reload. Setting this value throttles the reloads to once per the number of seconds. The default is 1 second. .TP .B verbosity:\fR This value specifies the verbosity level for (non\-debug) logging. Default is 0. 1 gives more information about incoming notifies and zone transfers. 2 lists soft warnings that are encountered. 3 prints more information. .IP Verbosity 0 will print warnings and errors, and other events that are important to keep NSD running. .IP Verbosity 1 prints additionally messages of interest. Successful notifies, successful incoming zone transfer (the zone is updated), failed incoming zone transfers or the inability to process zone updates. .IP Verbosity 2 prints additionally soft errors, like connection resets over TCP. And notify refusal, and axfr request refusals. .TP .B hide\-version:\fR Prevent NSD from replying with the version string on CHAOS class queries. Default is no. .TP .B log\-time\-ascii:\fR Log time in ascii, if "no" then in seconds epoch. Default is yes. This chooses the format when logging to file. The printout via syslog has a timestamp formatted by syslog. .TP .B round\-robin:\fR Enable round robin rotation of records in the answer. This changes the order of records in the answer and this may balance load across them. The default is no. .TP .B minimal\-responses:\fR Enable minimal responses for smaller answers. This makes packets smaller. Extra data is only added for referrals, when it is really necessary. This is different from the \-\-enable-minimal-responses configure time option, that reduces packets, but exactly to the fragmentation length, the nsd.conf option reduces packets as small as possible. The default is no. .TP .B refuse\-any:\fR Refuse queries of type ANY. This is useful to stop query floods trying to get large responses. Note that rrl ratelimiting also has type ANY as a ratelimiting type. It sends truncation in response to UDP type ANY queries, and it allows TCP type ANY queries like normal. The default is no. .TP .B zonefiles\-check:\fR Make NSD check the mtime of zone files on start and sighup. If you disable it it starts faster (less disk activity in case of a lot of zones). The default is yes. The nsd\-control reload command reloads zone files regardless of this option. .TP .B zonefiles\-write:\fR Write changed secondary zones to their zonefile every N seconds. If the zone (pattern) configuration has "" zonefile, it is not written. Zones that have received zone transfer updates are written to their zonefile. Default is 0 (disabled) when there is a database, and 3600 (1 hour) when database is "". The database also commits zone transfer contents. You can configure it away from the default by putting the config statement for zonefiles\-write: after the database: statement in the config file. .\" rrlstart .TP .B rrl\-size:\fR This option gives the size of the hashtable. Default 1000000. More buckets use more memory, and reduce the chance of hash collisions. .TP .B rrl\-ratelimit:\fR The max qps allowed (from one query source). Default is @ratelimit_default@ (with a suggested 200 qps). If set to 0 then it is disabled (unlimited rate), also set the whitelist\-ratelimit to 0 to disable ratelimit processing. If you set verbosity to 2 the blocked and unblocked subnets are logged. Blocked queries are blocked and some receive TCP fallback replies. Once the rate limit is reached, NSD begins dropping responses. However, one in every "rrl\-slip" number of responses is allowed, with the TC bit set. If slip is set to 2, the outgoing response rate will be halved. If it's set to 3, the outgoing response rate will be one\-third, and so on. If you set rrl\-slip to 10, traffic is reduced to 1/10th. Ratelimit options rrl\-ratelimit, rrl\-size and rrl\-whitelist\-ratelimit are updated when nsd\-control reconfig is done (also the zone\-specific ratelimit options are updated). .TP .B rrl\-slip:\fR This option controls the number of packets discarded before we send back a SLIP response (a response with "truncated" bit set to one). 0 disables the sending of SLIP packets, 1 means every query will get a SLIP response. Default is 2, cuts traffic in half and legit users have a fair chance to get a +TC response. .TP .B rrl\-ipv4\-prefix\-length:\fR IPv4 prefix length. Addresses are grouped by netblock. Default 24. .TP .B rrl\-ipv6\-prefix\-length:\fR IPv6 prefix length. Addresses are grouped by netblock. Default 64. .TP .B rrl\-whitelist\-ratelimit:\fR The max qps for query sorts for a source, which have been whitelisted. Default @ratelimit_default@ (with a suggested 2000 qps). With the rrl\-whitelist option you can set specific queries to receive this qps limit instead of the normal limit. With the value 0 the rate is unlimited. .\" rrlend .SS "Remote Control" The .B remote\-control: clause is used to set options for using the \fInsd\-control\fR(8) tool to give commands to the running NSD server. It is disabled by default, and listens for localhost by default. It uses TLS over TCP where the server and client authenticate to each other with self\-signed certificates. The self\-signed certificates can be generated with the \fInsd\-control\-setup\fR tool. The key files are read by NSD before the chroot and before dropping user permissions, so they can be outside the chroot and readable by the superuser only. .TP .B control\-enable:\fR Enable remote control, default is no. .TP .B control\-interface:\fR NSD will bind to the listed addresses to service control requests (on TCP). Can be given multiple times to bind multiple ip\-addresses. Use 0.0.0.0 and ::0 to service the wildcard interface. If none are given NSD listens to the localhost 127.0.0.1 and ::1 interfaces for control, if control is enabled with control\-enable. .IP With an absolute path, a unix local named pipe is used for control. The file is created with user and group that is configured and access bits are set to allow members of the group access. Further access can be controlled by setting permissions on the directory containing the control socket file. The key and cert files are not used when control is via the named pipe, because access control is via file and directory permission. .TP .B control\-port:\fR The port number for remote control service. 8952 by default. .TP .B server\-key\-file:\fR Path to the server private key, by default .IR @configdir@/nsd_server.key . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by the nsd server, but not by \fInsd\-control\fR. .TP .B server\-cert\-file:\fR Path to the server self signed certificate, by default .IR @configdir@/nsd_server.pem . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by the nsd server, and also by \fInsd\-control\fR. .TP .B control\-key\-file:\fR Path to the control client private key, by default .IR @configdir@/nsd_control.key . This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by \fInsd\-control\fR. .TP .B control\-cert\-file:\fR Path to the control client certificate, by default .IR @configdir@/nsd_control.pem . This certificate has to be signed with the server certificate. This file is generated by the \fInsd\-control\-setup\fR utility. This file is used by \fInsd\-control\fR. .SS "Pattern Options" The .B pattern: clause is used to denote a set of options to apply to some zones. The same zone options as for a zone are allowed. .TP .B name:\fR The name of the pattern. This is a (case sensitive) string. The pattern names that start with "_implicit_" are used internally for zones that have no pattern (they are defined in nsd.conf directly). .TP .B include\-pattern:\fR The options from the given pattern are included at this point in this pattern. The referenced pattern must be defined above this one. .TP .B :\fR The zone options such as .BR zonefile , .BR allow\-notify , .BR request\-xfr , .BR allow\-axfr\-fallback , .BR notify , .BR notify\-retry , .BR provide\-xfr , .BR zonestats , and .B outgoing\-interface can be given. They are applied to the patterns and zones that include this pattern. .SS "Zone Options" .LP For every zone the options need to be specified in one .B zone: clause. The access control list elements can be given multiple times to add multiple servers. These elements need to be added explicitly. .LP For zones that are configured in the \fInsd.conf\fR config file their settings are hardcoded (in an implicit pattern for themselves only) and they cannot be deleted via delzone, but remove them from the config file and repattern. .TP .B name:\fR The name of the zone. This is the domain name of the apex of the zone. May end with a '.' (in FQDN notation). For example "example.com", "sub.example.net.". This attribute must be present in each zone. .TP .B zonefile:\fR The file containing the zone information. If this attribute is present it is used to read and write the zone contents. If the attribute is absent it prevents writing out of the zone. .IP The string is processed so that one string can be used (in a pattern) for a lot of different zones. If the label or character does not exist the percent-character is replaced with a period for output (i.e. for the third character in a two letter domain name). .IP .B %s\fR is replaced with the zone name. .IP .B %1\fR is replaced with the first character of the zone name. .IP .B %2\fR is replaced with the second character of the zone name. .IP .B %3\fR is replaced with the third character of the zone name. .IP .B %z\fR is replaced with the toplevel domain name of the zone. .IP .B %y\fR is replaced with the next label under the toplevel domain. .IP .B %x\fR is replaced with the next-next label under the toplevel domain. .TP .B allow\-notify:\fR Access control list. The listed (primary) address is allowed to send notifies to this (secondary) server. Notifies from unlisted or specifically BLOCKED addresses are discarded. If NOKEY is given no TSIG signature is required. BLOCKED supersedes other entries, other entries are scanned for a match in the order of the statements. .P .RS The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be a subnet of the form 1.2.3.4/24, or masked like 1.2.3.4&255.255.255.0 or a range of the form 1.2.3.4\-1.2.3.25. A port number can be added using a suffix of @number, for example 1.2.3.4@5300 or 1.2.3.4/24@5300 for port 5300. Note the ip\-spec ranges do not use spaces around the /, &, @ and \- symbols. .RE .TP .B request\-xfr:\fR [AXFR|UDP] Access control list. The listed address (the master) is queried for AXFR/IXFR on update. A port number can be added using a suffix of @number, for example 1.2.3.4@5300. The specified key is used during AXFR/IXFR. .P .RS If the AXFR option is given, the server will not be contacted with IXFR queries but only AXFR requests will be made to the server. This allows an NSD secondary to have a master server that runs NSD. If the AXFR option is left out then both IXFR and AXFR requests are made to the master server. .P If the UDP option is given, the secondary will use UDP to transmit the IXFR requests. You should deploy TSIG when allowing UDP transport, to authenticate notifies and zone transfers. Otherwise, NSD is more vulnerable for Kaminsky\-style attacks. If the UDP option is left out then IXFR will be transmitted using TCP. .RE .TP .B allow\-axfr\-fallback:\fR This option should be accompanied by request\-xfr. It (dis)allows NSD (as secondary) to fallback to AXFR if the primary name server does not support IXFR. Default is yes. .TP .B size\-limit\-xfr:\fR This option should be accompanied by request\-xfr. It specifies XFR temporary file size limit. It can be used to stop very large zone retrieval, that could otherwise use up a lot of memory and disk space. If this option is 0, unlimited. Default value is 0. .TP .B notify:\fR Access control list. The listed address (a secondary) is notified of updates to this zone. A port number can be added using a suffix of @number, for example 1.2.3.4@5300. The specified key is used to sign the notify. Only on secondary configurations will NSD be able to detect zone updates (as it gets notified itself, or refreshes after a time). .TP .B notify\-retry:\fR This option should be accompanied by notify. It sets the number of retries when sending notifies. .TP .B provide\-xfr:\fR Access control list. The listed address (a secondary) is allowed to request AXFR from this server. Zone data will be provided to the address. The specified key is used during AXFR. For unlisted or BLOCKED addresses no data is provided, requests are discarded. BLOCKED supersedes other entries, other entries are scanned for a match in the order of the statements. NSD provides AXFR for its secondaries, but IXFR is not implemented (IXFR is implemented for request\-xfr, but not for provide\-xfr). .P .RS The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be a subnet of the form 1.2.3.4/24, or masked like 1.2.3.4&255.255.255.0 or a range of the form 1.2.3.4\-1.2.3.25. A port number can be added using a suffix of @number, for example 1.2.3.4@5300 or 1.2.3.4/24@5300 for port 5300. Note the ip\-spec ranges do not use spaces around the /, &, @ and \- symbols. .RE .TP .B outgoing\-interface:\fR Access control list. The listed address is used to request AXFR|IXFR (in case of a secondary) or used to send notifies (in case of a primary). .P .RS The ip\-address is a plain IP address (IPv4 or IPv6). A port number can be added using a suffix of @number, for example 1.2.3.4@5300. .RE .TP .B max\-refresh\-time:\fR Limit refresh time for secondary zones. This is the timer which checks to see if the zone has to be refetched when it expires. Normally the value from the SOA record is used, but this option restricts that value. .TP .B min\-refresh\-time:\fR Limit refresh time for secondary zones. .TP .B max\-retry\-time:\fR Limit retry time for secondary zones. This is the timeout after a failed fetch attempt for the zone. Normally the value from the SOA record is used, but this option restricts that value. .TP .B min\-retry\-time:\fR Limit retry time for secondary zones. .TP .B zonestats:\fR When compiled with \-\-enable\-zone\-stats NSD can collect statistics per zone. This name gives the group where statistics are added to. The groups are output from nsd\-control stats and stats_noreset. Default is "". You can use "%s" to use the name of the zone to track its statistics. If not compiled in, the option can be given but is ignored. .TP .B include\-pattern:\fR The options from the given pattern are included at this point. The referenced pattern must be defined above this zone. .\" rrlstart .TP .B rrl\-whitelist:\fR This option causes queries of this rrltype to be whitelisted, for this zone. They receive the whitelist\-ratelimit. You can give multiple lines, each enables a new rrltype to be whitelisted for the zone. Default has none whitelisted. The rrltype is the query classification that the NSD RRL employs to make different types not interfere with one another. The types are logged in the loglines when a subnet is blocked (in verbosity 2). The RRL classification types are: nxdomain, error, referral, any, rrsig, wildcard, nodata, dnskey, positive, all. .\" rrlend .TP .B multi\-master\-check:\fR Default no. If enabled, checks all masters for the last version. It uses the higher version of all the configured masters. Useful if you have multiple masters that have different version numbers served. .SS "Key Declarations" The .B key: clause establishes a key for use in access control lists. It has the following attributes. .TP .B name:\fR The key name. Used to refer to this key in the access control list. The key name has to be correct for tsig to work. This is because the key name is output on the wire. .TP .B algorithm:\fR Authentication algorithm for this key. Such as hmac\-md5, hmac\-sha1, hmac\-sha224, hmac\-sha256, hmac\-sha384 and hmac\-sha512. Can also be abbreviated as 'sha1', 'sha256'. Default is sha256. Algorithms are only available when they were compiled in (available in the crypto library). .TP .B secret:\fR The base64 encoded shared secret. It is possible to put the .B secret: declaration (and base64 blob) into a different file, and then to .B include: that file. In this way the key secret and the rest of the configuration file, which may have different security policies, can be split apart. The content of the secret is the agreed base64 secret content. To make it up, enter a password (its length must be a multiple of 4 characters, A\-Za\-z0\-9), or use dev-random output through a base64 encode filter. .SH "NSD CONFIGURATION FOR BIND9 HACKERS" BIND9 is a name server implementation with its own configuration file format, named.conf(5). BIND9 types zones as 'Master' or 'Slave'. .SS "Slave zones" For a slave zone, the master servers are listed. The master servers are queried for zone data, and are listened to for update notifications. In NSD these two properties need to be configured separately, by listing the master address in allow\-notify and request\-xfr statements. .P In BIND9 you only need to provide allow\-notify elements for any extra sources of notifications (i.e. the operators), NSD needs to have allow\-notify for both masters and operators. BIND9 allows additional transfer sources, in NSD you list those as request\-xfr. .P Here is an example of a slave zone in BIND9 syntax. .P # Config file for example.org options { .RS 5 dnssec\-enable yes; .RE .RS 0 }; .RE .LP key tsig.example.org. { .RS 5 algorithm hmac\-md5; .RE .RS 5 secret "aaaaaabbbbbbccccccdddddd"; .RE }; .LP server 162.0.4.49 { .RS 5 keys { tsig.example.org. ; }; .RE }; .LP zone "example.org" { .RS 5 type slave; .RE .RS 5 file "secondary/example.org.signed"; .RE .RS 5 masters { 162.0.4.49; }; .RE }; .P For NSD, DNSSEC is enabled automatically for zones that are signed. The dnssec\-enable statement in the options clause is not needed. In NSD keys are associated with an IP address in the access control list statement, therefore the server{} statement is not needed. Below is the same example in an NSD config file. .LP # Config file for example.org .RS 0 key: .RE .RS 5 name: tsig.example.org. .RE .RS 5 algorithm: hmac\-md5 .RE .RS 5 secret: "aaaaaabbbbbbccccccdddddd" .RE .LP zone: .RS 5 name: "example.org" .RE .RS 5 zonefile: "secondary/example.org.signed" .RE .RS 5 # the master is allowed to notify and will provide zone data. .RE .RS 5 allow\-notify: 162.0.4.49 NOKEY .RE .RS 5 request\-xfr: 162.0.4.49 tsig.example.org. .RE .P Notice that the master is listed twice, once to allow it to send notifies to this slave server and once to tell the slave server where to look for updates zone data. More allow\-notify and request\-xfr lines can be added to specify more masters. .P It is possible to specify extra allow\-notify lines for addresses that are also allowed to send notifications to this slave server. .SS "Master zones" For a master zone in BIND9, the slave servers are listed. These slave servers are sent notifications of updated and are allowed to request transfer of the zone data. In NSD these two properties need to be configured separately. .P Here is an example of a master zone in BIND9 syntax. .LP zone "example.nl" { .RS 5 type master; .RE .RS 5 file "example.nl"; .RE }; .LP In NSD syntax this becomes: .LP zone: .RS 5 name: "example.nl" .RE .RS 5 zonefile: "example.nl" .RE .RS 5 # allow anybody to request xfr. .RE .RS 5 provide\-xfr: 0.0.0.0/0 NOKEY .RE .RS 5 provide\-xfr: ::0/0 NOKEY .RE .P .RS 5 # to list a slave server you would in general give .RE .RS 5 # provide\-xfr: 1.2.3.4 tsig\-key.name. .RE .RS 5 # notify: 1.2.3.4 NOKEY .RE .SS "Other" NSD is an authoritative only DNS server. This means that it is meant as a primary or secondary server for zones, providing DNS data to DNS resolvers and caches. BIND9 can function as an authoritative DNS server, the configuration options for that are compared with those for NSD in this section. However, BIND9 can also function as a resolver or cache. The configuration options that BIND9 has for the resolver or caching thus have no equivalents for NSD. .SH "FILES" .TP "@dbfile@" default .B NSD database .TP @nsdconfigfile@ default .B NSD configuration file .SH "SEE ALSO" \fInsd\fR(8), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. .SH "BUGS" .B nsd.conf is parsed by a primitive parser, error messages may not be to the point. nsd-4.1.26/namedb.c0000664000175000017500000004314513237011655013432 0ustar wouterwouter/* * namedb.c -- common namedb operations. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "namedb.h" #include "nsec3.h" static domain_type * allocate_domain_info(domain_table_type* table, const dname_type* dname, domain_type* parent) { domain_type *result; assert(table); assert(dname); assert(parent); result = (domain_type *) region_alloc(table->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE result->dname #else result->node.key #endif = dname_partial_copy( table->region, dname, domain_dname(parent)->label_count + 1); result->parent = parent; result->wildcard_child_closest_match = result; result->rrsets = NULL; result->usage = 0; #ifdef NSEC3 result->nsec3 = NULL; #endif result->is_existing = 0; result->is_apex = 0; assert(table->numlist_last); /* it exists because root exists */ /* push this domain at the end of the numlist */ result->number = table->numlist_last->number+1; result->numlist_next = NULL; result->numlist_prev = table->numlist_last; table->numlist_last->numlist_next = result; table->numlist_last = result; return result; } #ifdef NSEC3 void allocate_domain_nsec3(domain_table_type* table, domain_type* result) { if(result->nsec3) return; result->nsec3 = (struct nsec3_domain_data*) region_alloc(table->region, sizeof(struct nsec3_domain_data)); result->nsec3->nsec3_cover = NULL; result->nsec3->nsec3_wcard_child_cover = NULL; result->nsec3->nsec3_ds_parent_cover = NULL; result->nsec3->nsec3_is_exact = 0; result->nsec3->nsec3_ds_parent_is_exact = 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; } #endif /* NSEC3 */ /** make the domain last in the numlist, changes numbers of domains */ static void numlist_make_last(domain_table_type* table, domain_type* domain) { uint32_t sw; domain_type* last = table->numlist_last; if(domain == last) return; /* swap numbers with the last element */ sw = domain->number; domain->number = last->number; last->number = sw; /* swap list position with the last element */ assert(domain->numlist_next); assert(last->numlist_prev); if(domain->numlist_next != last) { /* case 1: there are nodes between domain .. last */ domain_type* span_start = domain->numlist_next; domain_type* span_end = last->numlist_prev; /* these assignments walk the new list from start to end */ if(domain->numlist_prev) domain->numlist_prev->numlist_next = last; last->numlist_prev = domain->numlist_prev; last->numlist_next = span_start; span_start->numlist_prev = last; span_end->numlist_next = domain; domain->numlist_prev = span_end; domain->numlist_next = NULL; } else { /* case 2: domain and last are neighbors */ /* these assignments walk the new list from start to end */ if(domain->numlist_prev) domain->numlist_prev->numlist_next = last; last->numlist_prev = domain->numlist_prev; last->numlist_next = domain; domain->numlist_prev = last; domain->numlist_next = NULL; } table->numlist_last = domain; } /** pop the biggest domain off the numlist */ static domain_type* numlist_pop_last(domain_table_type* table) { domain_type* d = table->numlist_last; table->numlist_last = table->numlist_last->numlist_prev; if(table->numlist_last) table->numlist_last->numlist_next = NULL; return d; } /** see if a domain is eligible to be deleted, and thus is not used */ static int domain_can_be_deleted(domain_type* domain) { domain_type* n; /* it has data or it has usage, do not delete it */ if(domain->rrsets) return 0; if(domain->usage) return 0; n = domain_next(domain); /* it has children domains, do not delete it */ if(n && domain_is_subdomain(n, domain)) return 0; return 1; } #ifdef NSEC3 /** see if domain is on the prehash list */ int domain_is_prehash(domain_table_type* table, domain_type* domain) { if(domain->nsec3 && (domain->nsec3->prehash_prev || domain->nsec3->prehash_next)) return 1; return (table->prehash_list == domain); } /** remove domain node from NSEC3 tree in hash space */ void zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node) { if(!node->key) return; rbtree_delete(tree, node->key); /* note that domain is no longer in the tree */ node->key = NULL; } /** clear the prehash list */ void prehash_clear(domain_table_type* table) { domain_type* d = table->prehash_list, *n; while(d) { n = d->nsec3->prehash_next; d->nsec3->prehash_prev = NULL; d->nsec3->prehash_next = NULL; d = n; } table->prehash_list = NULL; } /** add domain to prehash list */ void prehash_add(domain_table_type* table, domain_type* domain) { if(domain_is_prehash(table, domain)) return; allocate_domain_nsec3(table, domain); domain->nsec3->prehash_next = table->prehash_list; if(table->prehash_list) table->prehash_list->nsec3->prehash_prev = domain; table->prehash_list = domain; } /** remove domain from prehash list */ void prehash_del(domain_table_type* table, domain_type* domain) { if(domain->nsec3->prehash_next) domain->nsec3->prehash_next->nsec3->prehash_prev = domain->nsec3->prehash_prev; if(domain->nsec3->prehash_prev) domain->nsec3->prehash_prev->nsec3->prehash_next = domain->nsec3->prehash_next; else table->prehash_list = domain->nsec3->prehash_next; domain->nsec3->prehash_next = NULL; domain->nsec3->prehash_prev = NULL; } #endif /* NSEC3 */ /** perform domain name deletion */ static void do_deldomain(namedb_type* db, domain_type* domain) { assert(domain && domain->parent); /* exists and not root */ /* first adjust the number list so that domain is the last one */ numlist_make_last(db->domains, domain); /* pop off the domain from the number list */ (void)numlist_pop_last(db->domains); #ifdef NSEC3 /* if on prehash list, remove from prehash */ if(domain_is_prehash(db->domains, domain)) prehash_del(db->domains, domain); /* see if nsec3-nodes are used */ if(domain->nsec3) { 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_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->ds_parent_hash->node); if(domain->nsec3->hash_wc) { region_recycle(db->domains->region, domain->nsec3->hash_wc, sizeof(nsec3_hash_wc_node_type)); } if(domain->nsec3->ds_parent_hash) { region_recycle(db->domains->region, domain->nsec3->ds_parent_hash, sizeof(nsec3_hash_node_type)); } region_recycle(db->domains->region, domain->nsec3, sizeof(struct nsec3_domain_data)); } #endif /* NSEC3 */ /* see if this domain is someones wildcard-child-closest-match, * which can only be the parent, and then it should use the * one-smaller than this domain as closest-match. */ if(domain->parent->wildcard_child_closest_match == domain) domain->parent->wildcard_child_closest_match = domain_previous_existing_child(domain); /* actual removal */ #ifdef USE_RADIX_TREE radix_delete(db->domains->nametree, domain->rnode); #else rbtree_delete(db->domains->names_to_domains, domain->node.key); #endif region_recycle(db->domains->region, domain_dname(domain), dname_total_size(domain_dname(domain))); region_recycle(db->domains->region, domain, sizeof(domain_type)); } void domain_table_deldomain(namedb_type* db, domain_type* domain) { while(domain_can_be_deleted(domain)) { /* delete it */ do_deldomain(db, domain); /* test parent */ domain = domain->parent; } } /** clear hash tree */ void hash_tree_clear(rbtree_type* tree) { rbnode_type* n; if(!tree) return; /* note that elements are no longer in the tree */ for(n=rbtree_first(tree); n!=RBTREE_NULL; n=rbtree_next(n)) { n->key = NULL; } tree->count = 0; tree->root = RBTREE_NULL; } void hash_tree_delete(region_type* region, rbtree_type* tree) { region_recycle(region, tree, sizeof(rbtree_type)); } /** add domain nsec3 node to hashedspace tree */ void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree, int (*cmpf)(const void*, const void*), domain_type* domain, rbnode_type* node) { if(!*tree) *tree = rbtree_create(region, cmpf); if(node->key) return; memset(node, 0, sizeof(rbnode_type)); node->key = domain; rbtree_insert(*tree, node); } domain_table_type * domain_table_create(region_type* region) { const dname_type* origin; domain_table_type* result; domain_type* root; assert(region); origin = dname_make(region, (uint8_t *) "", 0); root = (domain_type *) region_alloc(region, sizeof(domain_type)); #ifdef USE_RADIX_TREE root->dname #else root->node.key #endif = origin; root->parent = NULL; root->wildcard_child_closest_match = root; root->rrsets = NULL; root->number = 1; /* 0 is used for after header */ root->usage = 1; /* do not delete root, ever */ root->is_existing = 0; root->is_apex = 0; root->numlist_prev = NULL; root->numlist_next = NULL; #ifdef NSEC3 root->nsec3 = NULL; #endif result = (domain_table_type *) region_alloc(region, sizeof(domain_table_type)); result->region = region; #ifdef USE_RADIX_TREE result->nametree = radix_tree_create(region); root->rnode = radname_insert(result->nametree, dname_name(root->dname), root->dname->name_size, root); #else result->names_to_domains = rbtree_create( region, (int (*)(const void *, const void *)) dname_compare); rbtree_insert(result->names_to_domains, (rbnode_type *) root); #endif result->root = root; result->numlist_last = root; #ifdef NSEC3 result->prehash_list = NULL; #endif return result; } int domain_table_search(domain_table_type *table, const dname_type *dname, domain_type **closest_match, domain_type **closest_encloser) { int exact; uint8_t label_match_count; assert(table); assert(dname); assert(closest_match); assert(closest_encloser); #ifdef USE_RADIX_TREE exact = radname_find_less_equal(table->nametree, dname_name(dname), dname->name_size, (struct radnode**)closest_match); *closest_match = (domain_type*)((*(struct radnode**)closest_match)->elem); #else exact = rbtree_find_less_equal(table->names_to_domains, dname, (rbnode_type **) closest_match); #endif assert(*closest_match); *closest_encloser = *closest_match; if (!exact) { label_match_count = dname_label_match_count( domain_dname(*closest_encloser), dname); assert(label_match_count < dname->label_count); while (label_match_count < domain_dname(*closest_encloser)->label_count) { (*closest_encloser) = (*closest_encloser)->parent; assert(*closest_encloser); } } return exact; } domain_type * domain_table_find(domain_table_type* table, const dname_type* dname) { domain_type* closest_match; domain_type* closest_encloser; int exact; exact = domain_table_search( table, dname, &closest_match, &closest_encloser); return exact ? closest_encloser : NULL; } domain_type * domain_table_insert(domain_table_type* table, const dname_type* dname) { domain_type* closest_match; domain_type* closest_encloser; domain_type* result; int exact; assert(table); assert(dname); exact = domain_table_search( table, dname, &closest_match, &closest_encloser); if (exact) { result = closest_encloser; } else { assert(domain_dname(closest_encloser)->label_count < dname->label_count); /* Insert new node(s). */ do { result = allocate_domain_info(table, dname, closest_encloser); #ifdef USE_RADIX_TREE result->rnode = radname_insert(table->nametree, dname_name(result->dname), result->dname->name_size, result); #else rbtree_insert(table->names_to_domains, (rbnode_type *) result); #endif /* * If the newly added domain name is larger * than the parent's current * wildcard_child_closest_match but smaller or * equal to the wildcard domain name, update * the parent's wildcard_child_closest_match * field. */ if (label_compare(dname_name(domain_dname(result)), (const uint8_t *) "\001*") <= 0 && dname_compare(domain_dname(result), domain_dname(closest_encloser->wildcard_child_closest_match)) > 0) { closest_encloser->wildcard_child_closest_match = result; } closest_encloser = result; } while (domain_dname(closest_encloser)->label_count < dname->label_count); } return result; } domain_type *domain_previous_existing_child(domain_type* domain) { domain_type* parent = domain->parent; domain = domain_previous(domain); while(domain && !domain->is_existing) { if(domain == parent) /* do not walk back above parent */ return parent; domain = domain_previous(domain); } return domain; } void domain_add_rrset(domain_type* domain, rrset_type* rrset) { #if 0 /* fast */ rrset->next = domain->rrsets; domain->rrsets = rrset; #else /* preserve ordering, add at end */ rrset_type** p = &domain->rrsets; while(*p) p = &((*p)->next); *p = rrset; rrset->next = 0; #endif while (domain && !domain->is_existing) { domain->is_existing = 1; /* does this name in existance update the parent's * wildcard closest match? */ if(domain->parent && label_compare(dname_name(domain_dname(domain)), (const uint8_t *) "\001*") <= 0 && dname_compare(domain_dname(domain), domain_dname(domain->parent->wildcard_child_closest_match)) > 0) { domain->parent->wildcard_child_closest_match = domain; } domain = domain->parent; } } rrset_type * domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type) { rrset_type* result = domain->rrsets; while (result) { if (result->zone == zone && rrset_rrtype(result) == type) { return result; } result = result->next; } return NULL; } rrset_type * domain_find_any_rrset(domain_type* domain, zone_type* zone) { rrset_type* result = domain->rrsets; while (result) { if (result->zone == zone) { return result; } result = result->next; } return NULL; } zone_type * domain_find_zone(namedb_type* db, domain_type* domain) { rrset_type* rrset; while (domain) { if(domain->is_apex) { for (rrset = domain->rrsets; rrset; rrset = rrset->next) { if (rrset_rrtype(rrset) == TYPE_SOA) { return rrset->zone; } } return namedb_find_zone(db, domain_dname(domain)); } domain = domain->parent; } return NULL; } zone_type * domain_find_parent_zone(namedb_type* db, zone_type* zone) { rrset_type* rrset; assert(zone); for (rrset = zone->apex->rrsets; rrset; rrset = rrset->next) { if (rrset->zone != zone && rrset_rrtype(rrset) == TYPE_NS) { return rrset->zone; } } /* the NS record in the parent zone above this zone is not present, * workaround to find that parent zone anyway */ if(zone->apex->parent) return domain_find_zone(db, zone->apex->parent); return NULL; } domain_type * domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns) { while (domain && domain != zone->apex) { *ns = domain_find_rrset(domain, zone, TYPE_NS); if (*ns) return domain; domain = domain->parent; } *ns = NULL; return NULL; } domain_type * find_dname_above(domain_type* domain, zone_type* zone) { domain_type* d = domain->parent; while(d && d != zone->apex) { if(domain_find_rrset(d, zone, TYPE_DNAME)) return d; d = d->parent; } return NULL; } int domain_is_glue(domain_type* domain, zone_type* zone) { rrset_type* unused; domain_type* ns_domain = domain_find_ns_rrsets(domain, zone, &unused); return (ns_domain != NULL && domain_find_rrset(ns_domain, zone, TYPE_SOA) == NULL); } domain_type * domain_wildcard_child(domain_type* domain) { domain_type* wildcard_child; assert(domain); assert(domain->wildcard_child_closest_match); wildcard_child = domain->wildcard_child_closest_match; if (wildcard_child != domain && label_is_wildcard(dname_name(domain_dname(wildcard_child)))) { return wildcard_child; } else { return NULL; } } int zone_is_secure(zone_type* zone) { assert(zone); return zone->is_secure; } uint16_t rr_rrsig_type_covered(rr_type* rr) { assert(rr->type == TYPE_RRSIG); assert(rr->rdata_count > 0); assert(rdata_atom_size(rr->rdatas[0]) == sizeof(uint16_t)); return ntohs(* (uint16_t *) rdata_atom_data(rr->rdatas[0])); } zone_type * namedb_find_zone(namedb_type* db, const dname_type* dname) { struct radnode* n = radname_search(db->zonetree, dname_name(dname), dname->name_size); if(n) return (zone_type*)n->elem; return NULL; } rrset_type * domain_find_non_cname_rrset(domain_type* domain, zone_type* zone) { /* find any rrset type that is not allowed next to a CNAME */ /* nothing is allowed next to a CNAME, except RRSIG, NSEC, NSEC3 */ rrset_type *result = domain->rrsets; while (result) { if (result->zone == zone && /* here is the list of exceptions*/ rrset_rrtype(result) != TYPE_CNAME && rrset_rrtype(result) != TYPE_RRSIG && rrset_rrtype(result) != TYPE_NXT && rrset_rrtype(result) != TYPE_SIG && rrset_rrtype(result) != TYPE_NSEC && rrset_rrtype(result) != TYPE_NSEC3 ) { return result; } result = result->next; } return NULL; } int namedb_lookup(struct namedb* db, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser) { return domain_table_search( db->domains, dname, closest_match, closest_encloser); } nsd-4.1.26/answer.h0000664000175000017500000000176310372122440013500 0ustar wouterwouter/* * answer.h -- manipulating query answers and encoding them. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _ANSWER_H_ #define _ANSWER_H_ #include #include "dns.h" #include "namedb.h" #include "packet.h" #include "query.h" /* * Structure used to keep track of RRsets that need to be stored in * the answer packet. */ typedef struct answer answer_type; struct answer { size_t rrset_count; rrset_type *rrsets[MAXRRSPP]; domain_type *domains[MAXRRSPP]; rr_section_type section[MAXRRSPP]; }; void encode_answer(query_type *q, const answer_type *answer); void answer_init(answer_type *answer); /* * Add the specified RRset to the answer in the specified section. If * the RRset is already present and in the same (or "higher") section * return 0, otherwise return 1. */ int answer_add_rrset(answer_type *answer, rr_section_type section, domain_type *domain, rrset_type *rrset); #endif /* _ANSWER_H_ */ nsd-4.1.26/difffile.h0000664000175000017500000001114113040156013013736 0ustar wouterwouter/* * difffile.h - nsd.diff file handling header file. Read/write diff files. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DIFFFILE_H #define DIFFFILE_H #include "rbtree.h" #include "namedb.h" #include "options.h" #include "udb.h" struct nsd; struct nsdst; #define DIFF_PART_XXFR ('X'<<24 | 'X'<<16 | 'F'<<8 | 'R') #define DIFF_PART_XFRF ('X'<<24 | 'F'<<16 | 'R'<<8 | 'F') /* write an xfr packet data to the diff file, type=IXFR. The diff file is created if necessary, with initial header(notcommitted). */ void diff_write_packet(const char* zone, const char* pat, uint32_t old_serial, uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len, struct nsd* nsd, uint64_t filenumber); /* * Overwrite header of diff file with committed vale and other data. * append log string. */ void diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial, uint32_t num_parts, uint8_t commit, const char* log_msg, struct nsd* nsd, uint64_t filenumber); /* * These functions read parts of the diff file. */ int diff_read_32(FILE *in, uint32_t* result); int diff_read_8(FILE *in, uint8_t* result); int diff_read_str(FILE* in, char* buf, size_t len); /* delete the RRs for a zone from memory */ void delete_zone_rrs(namedb_type* db, zone_type* zone); /* delete an RR */ int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, region_type* temp_region, struct udb_ptr* udbz, int* softfail); /* add an RR */ int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, struct udb_ptr* udbz, int* softfail); /* task udb structure */ struct task_list_d { /** next task in list */ udb_rel_ptr next; /** task type */ enum { /** expire or un-expire a zone */ task_expire, /** apply an ixfr or axfr to a zone */ task_apply_xfr, /** soa info for zone */ task_soa_info, /** check mtime of zonefiles and read them, done on SIGHUP */ task_check_zonefiles, /** write zonefiles (if changed) */ task_write_zonefiles, /** set verbosity */ task_set_verbosity, /** statistic info */ task_stat_info, /** add a zone */ task_add_zone, /** delete zone */ task_del_zone, /** add TSIG key */ task_add_key, /** delete TSIG key */ task_del_key, /** add pattern */ task_add_pattern, /** delete pattern */ task_del_pattern, /** options change */ task_opt_change, /** zonestat increment */ task_zonestat_inc } task_type; uint32_t size; /* size of this struct */ /** soainfo: zonename dname, soaRR wireform */ /** expire: zonename, boolyesno */ /** apply_xfr: zonename, serials, yesno is filenamecounter */ uint32_t oldserial, newserial; /** general variable. for some used to see if zname is present. */ uint64_t yesno; struct dname zname[0]; }; #define TASKLIST(ptr) ((struct task_list_d*)UDB_PTR(ptr)) /** create udb for tasks */ struct udb_base* task_file_create(const char* file); void task_remap(udb_base* udb); void task_process_sync(udb_base* udb); void task_clear(udb_base* udb); void task_new_soainfo(udb_base* udb, udb_ptr* last, struct zone* z, int gone); void task_new_expire(udb_base* udb, udb_ptr* last, const struct dname* z, int expired); void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat, size_t child_count); void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone); void task_new_write_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone); void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v); void task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone, const char* pattern, unsigned zonestatid); void task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname); void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key); void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name); void task_new_add_pattern(udb_base* udb, udb_ptr* last, struct pattern_options* p); void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name); void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt); void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz); int task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* zone, uint32_t old_serial, uint32_t new_serial, uint64_t filenumber); void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task); void task_process_expire(namedb_type* db, struct task_list_d* task); #endif /* DIFFFILE_H */ nsd-4.1.26/doc/0000775000175000017500000000000013401455025012572 5ustar wouterwouternsd-4.1.26/doc/NSD-DIFFFILE0000664000175000017500000000274312204670310014311 0ustar wouterwouterDIFF support file format. This file contains changes to the main NSD-DATABASE file. The file contents is in network format. The file is a transfer, with a header and a number of data segments. - File starts with 32bit value 'XFRF' - header with: - 8bit: commit=1(IXFR is OK) or rollback=0(ignore that IXFR). - 32 bit number of packets that are to be applied. 0 if file not completed. - timestamp of endtime of download (64bitsec,32bitusec). - 32 bit old serial number. (to check that db-serial is unchanged). or 0 if no serial available yet. - 32 bit new serial number. - timestamp of starttime of download (64bitsec,32bitusec). - zone name (string). - pattern name: so that a newly created zone for which the zone transfer is processed before the config-add task can be created. same string format with 32bitcount with name of the pattern. - a number of parts that start with 'XXFR' - 32 bits length field. - length bytes of content. contents is the IXFR or AXFR packet contents, max 64K. - 32 bits repeat of the length field. at end of file a log string space for a text string message (preceded by 32bitcount), i.e. 'at time came from , tsig checked with key '. or rejected . The length fields and type fields check that the input is formatted, and complete otherwise an error occurred (like, disk failure). The commit flag is only set after the write of the entire file has completed (rewind, overwrite commit value with true). nsd-4.1.26/doc/differences.tex0000664000175000017500000007024110477245127015607 0ustar wouterwouter% DIFFERENCES NSD 3 and other name servers. \documentclass[twoside,titlepage,english]{nlnetlabs} \newcites{rfc}{RFC references} \def\nlnetlabsno{2006-004} \rcsdetails{$Id: differences.tex 2438 2006-09-05 09:58:47Z wouter $} % Prints RCS details at the bottom of the page. \title{Response Differences between\\ NSD and other DNS Servers} \author{ %This escape is needed. Because of wrapping by hyperref \texorpdfstring{ Jelte Jansen\thanks{\href{mailto:jelte@nlnetlabs.nl}{jelte@nlnetlabs.nl}}, \textsl{NLnet Labs}\\ Wouter Wijngaards\thanks{\href{mailto:wouter@nlnetlabs.nl}{wouter@nlnetlabs.nl}}, \textsl{NLnet Labs} } {Jelte Jansen, Wouter C.A. Wijngaards} } \date{ \today } \begin{document} \flushbottom \maketitle{} \begin{abstract} This note describes observed differences in responses between NSD and other DNS server implementations. NSD 3.0.0 is compared to NSD 2.3.6, BIND 8.4.7 and BIND 9.3.2. Differences in answers to captured queries from resolvers are tallied and analyzed. No interoperability problems are found. \end{abstract} \tableofcontents \newpage \section{Introduction} The NSD name server is compared to other DNS server implementations in order to assess server interoperability. The goal is to observe differences in the answers that the name servers provide. These differences are categorized and counted. We used BIND 8 and BIND 9 versions to compare against. Also regression tests have been run on our testlab, comparing NSD 2 versus NSD 3. Our method uses a set of queries captured from production name servers. These queries are sent over UDP to a name server set up to serve a particular zone. Then the responses from the name server are recorded. For every query, the different answers provided by the server implementations are compared. Unparseable answers and no answers from the servers are handled identically by the comparison software. This is not a problem because both BIND and NSD are mature and stable DNS implementations, all answers they send are parseable. Only in a very few cases, where the query is very badly formed, no answers are sent back. The differences are found by replaying captured DNS query traces from the NL TLD and from the root zone against different name servers. The differences in the answers are then analyzed, by first performing a byte-comparison on the packets. If the packets are binary different, the contents are parsed, thus removing differences in domain name compression, and normalized (sorted, lowercase) in presentation. If the results do not match after normalization, then a list of difference categories is consulted. The difference is classified as the first category that matches. If a difference in answers does not match any category, then the process stops and the user is notified. All the differences are categorized for the traces we present. In addition, we gratefully made use of the PROTOS DNS tool developed at the University of Oulu which they made publicly available at \href{http://www.ee.oulu.fi/research/ouspg/protos/testing/c09/dns} {the protos webpage}\footnote{http://www.ee.oulu.fi/research/ouspg/protos/testing/c09/dns} and played the queries against the authoritative name servers. We fixed a packet parsing error in NSD3-prerelease and both NSD3 and BIND 9.3.2 remained running and responsive. Additionally we used the faulty DNS query traces in the wiki-ethereal repository. These can be found in \href{http://wiki.ethereal.com/SampleCaptures} {the ethereal wiki}\footnote{http://wiki.ethereal.com/SampleCaptures}. These traces posed no problem for BIND and NSD, mostly FORMERR answers. A previous document DIFFERENCES between BIND 8.4.4 and NSD 2.0.0 can be found in the NSD 2.x package. In the places where differences have been found between BIND and NSD, in the authors' opinion, no interoperability problems result for resolvers. \section{Response differences between BIND 9.3.2 and NSD 3.0.0} In this section the response differences between BIND 9.3.2 and NSD 3.0.0 are presented and analyzed. We start in Section~\ref{root_b932nsd3} and Section~\ref{nl_b932nsd3} with presenting the difference statistics for two test traces. Then in Section~\ref{sec:features} and Section~\ref{sec:funcdiff} the difference categories are explained in more detail. \subsection{Comparison of responses to root queries} \label{root_b932nsd3} Comparison between NSD 3.0.0 and BIND 9.3.2 for a root trace. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ d-additional (\ref{d-additional}) & 455607 & 59.19\% \\ n-clrdobit (\ref{n-clrdobit}) & 208389 & 27.07\% \\ b-soattl (\ref{b-soattl}) & 101707 & 13.21\% \\ n-update (\ref{n-update}) & 1858 & 0.24\% \\ d-hostname (\ref{d-hostname}) & 1032 & 0.13\% \\ d-formerrquery (\ref{d-formerrquery}) & 773 & 0.10\% \\ b-class0 (\ref{b-class0}) & 264 & 0.03\% \\ d-refusedquery (\ref{d-refusedquery}) & 79 & 0.01\% \\ d-notify (\ref{d-notify}) & 18 & 0.00\% \\ b-mailb (\ref{b-mailb}) & 7 & 0.00\% \\ n-tcinquery (\ref{n-tcinquery}) & 6 & 0.00\% \\ b-classany-nxdomain (\ref{b-classany-nxdomain}) & 5 & 0.00\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 4 & 0.00\% \\ n-ixfr-notimpl (\ref{n-ixfr-notimpl}) & 3 & 0.00\% \\ d-version (\ref{d-version}) & 1 & 0.00\% \\ Total number of differences: & 769753 & 100\% \\ Number of packets the same after normalization:&1474863 \\ Number of packets exactly the same on the wire:& 59161 \\ Total number of packets inspected: &2244616 \\ \end{tabular} For each type of difference the number of packets in the trace that match that difference are shown. The section where that difference is analyzed is shown in parenthesis after the difference name. The percentage of differences explained by the difference category is listed. Adding up the packets that are different gives the total number of differences, or 100\% of the differences. The number of packets after normalization includes the number of packets that are the same on the wire. The total number of query packets is displayed at the bottom of the table. \subsection{Comparison of responses to NL TLD queries} \label{nl_b932nsd3} Comparison between NSD 3.0.0 and BIND 9.3.2, for a trace for .nl. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ d-unknown-opcode (\ref{d-unknown-opcode}) & 2541 & 26.44\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 1817 & 18.91\% \\ n-clrdobit (\ref{n-clrdobit}) & 1495 & 15.56\% \\ b-soattl (\ref{b-soattl}) & 1120 & 11.65\% \\ n-update (\ref{n-update}) & 990 & 10.30\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 847 & 8.81\% \\ d-hostname (\ref{d-hostname}) & 531 & 5.52\% \\ d-notify (\ref{d-notify}) & 98 & 1.02\% \\ b-upwards-ref (\ref{b-upwards-ref}) & 78 & 0.81\% \\ n-clrcdbit (\ref{n-clrcdbit}) & 63 & 0.66\% \\ d-version (\ref{d-version}) & 22 & 0.23\% \\ b-noglue-nsquery (\ref{b-noglue-nsquery}) & 8 & 0.08\% \\ b8-badedns0 (\ref{b8-badedns0}) & 1 & 0.01\% \\ Total number of differences: & 9611 & 100\% \\ Number of packets the same after normalization: & 90389 \\ Number of packets exactly the same on the wire: & 52336 \\ Total number of packets inspected: & 100000 \\ \end{tabular} \subsection{Features} \label{sec:features} In this section we enumerate a number of differences between BIND 9.3.2 and NSD 3.0.0 that cannot be immediately explained as design choices. These features could be seen as bugs in software or protocol specs, except that they do not lead to interoperability problems. \subsubsection{n-clrdobit - NSD clears DO bit in response} \label{n-clrdobit} NSD clears the DO bit in answers to queries with the DO bit. BIND copies the DO bit to the answer. \vspace{-8pt}\subparagraph{Analysis:} In RFC4035\cite{rfc4035} the DO bit is not specified for answers. In the examples section of that RFC the DO bit is shown for signed dig responses, although this could refer to the query or the answer. NSD clears the DO bit for all answers, a decision based on speed: the EDNS record sent back by NSD is precompiled and not modified during answer processing. \subsubsection{n-clrcdbit - NSD clears CD bit in response} \label{n-clrcdbit} NSD clears the CD bit in answers to queries with the CD bit. BIND copies the CD bit to the answer. \vspace{-8pt}\subparagraph{Analysis:} RFC 4035\cite{rfc4035} asserts that the CD bit must be cleared for authoritative answers. The CD bit should be copied into the answer by recursive servers. BIND copies the CD bit for some formerr queries. \subsubsection{b-class0 - CLASS0 formerr in BIND} \label{b-class0} For CLASS0, you can get either FORMERR, from BIND or REFUSED, from NSD. \vspace{-8pt}\subparagraph{Analysis:} Difference in interpretation of the RFCs, a CLASS value of 0 is interpreted as a syntax error by BIND but as another valid class (that is not served) by NSD. Resolvers are unaffected for CLASS IN. \subsubsection{n-tcinquery - TC bit in query is formerr for NSD} \label{n-tcinquery} NSD returns FORMERR if tc bit is set in query. \vspace{-8pt}\subparagraph{Analysis:} Queries cannot be longer than 512 octets, since the DNS header is short and the query DNS name has a maximum length of 255 octets. Thus TC (TrunCation) cannot happen. Only one question per query packet is answered by NSD, this is a design decision. Some update, ixfr request, notify, gss-tsig TKEY sequence queries could theoretically carry longer data in the query from the client. In practice this does not happen, as 255 octet uncompressed names are not used. If this were to happen, the client could attempt a TCP connection immediately instead of setting a TC bit, or use EDNS0 to send longer packets. In this NSD is more strict in validation than BIND. \subsubsection{b-soattl - BIND sets SOA TTL in authority section to 0 for SOA queries} \label{b-soattl} This happens when asking for the SOA for a domain that is not served. \footnotesize \begin{verbatim} Query: ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0 ;; flags: rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA \end{verbatim} \normalsize Answer from BIND 9.3.2: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 6097 ;; flags: qr aa rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 0 IN SOA A.ROOT-SERVERS.NET. NSTLD.VERISIGN-GRS.COM. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 10 msec ;; SERVER: 127.0.0.1 ;; WHEN: Wed Aug 23 13:52:36 2006 ;; MSG SIZE rcvd: 100 \end{verbatim} \normalsize Answer from NSD 3: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 26095 ;; flags: qr aa rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; foo.bar. IN SOA ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 60 msec ;; SERVER: 127.0.0.1 ;; WHEN: Wed Aug 23 13:53:30 2006 ;; MSG SIZE rcvd: 100 \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} BIND conforms to internet-draft draft-andrews-dnsext-soa-discovery which has at the moment of code development not (yet) been published as RFC. NSD conforms to the RFCs. \subsubsection{b-classany-nxdomain - BIND gives an auth answer for class ANY nxdomain} \label{b-classany-nxdomain} A difference in behaviour for CLASS=ANY queries. For existing domains both BIND and NSD reply with AA bit cleared. For not existing domains (nxdomain) NSD replies with AA bit cleared. BIND replies with AA bit on and includes a SOA (CLASS=IN) for the zone, as for an authoritative nxdomain. Query: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 13328 ;; flags: ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruO. ANY MX \end{verbatim} \normalsize Answer from BIND 9.3.2: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 13328 ;; flags: qr aa ; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruo. ANY MX ;; ANSWER SECTION: ;; AUTHORITY SECTION: . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. ( 2006072801 1800 900 604800 86400) ;; ADDITIONAL SECTION: ;; Query time: 0 msec ;; WHEN: Wed Aug 23 13:58:51 2006 ;; MSG SIZE rcvd: 103 \end{verbatim} \normalsize Answer from NSD 3: \footnotesize \begin{verbatim} ;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 13328 ;; flags: qr ; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;; nslabs.ruo. ANY MX ;; ANSWER SECTION: ;; AUTHORITY SECTION: ;; ADDITIONAL SECTION: ;; Query time: 0 msec ;; WHEN: Wed Aug 23 13:58:51 2006 ;; MSG SIZE rcvd: 28 \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} Feature of BIND where it answers authoritatively for CLASS ANY nxdomain queries. \subsubsection{b-badquery-badanswer - BIND replies with bad answer for some bad queries} \label{b-badquery-badanswer} BIND replies with an answer packet that cannot be parsed, or does not answer at all. NSD always generates an answer, with the appropriate RCODE (mostly NOTIMPL and FORMERR, but also NXDOMAIN to NOTIFY queries). All these queries are malformed in some way. A (very simple) example of a query without an answer is a query packet of 18 zero bytes. For some queries no answer only happens when BIND is presented with a trace of queries, not for a single query. \vspace{-8pt}\subparagraph{Analysis:} BIND includes (part of) the unparseable question into the answer, or some internal state of BIND is affected by earlier queries. NSD manages to answer the malformed query. Note that NSD does not answer queries that are too short, or that have the QR bit set. NSD tries to be as liberal in what it accepts as possible. \subsection{Functionality Differences} \label{sec:funcdiff} The next group of differences are due to the fact that NSD does not implement some functionality that is requested by resolvers. This is a design choice and should not cause resolver problems at all, since responses to those requests are within protocol specs. \subsubsection{d-notify - different NOTIFY errors} \label{d-notify} BIND and NSD give different errors for notify queries. The servers are started without any configuration for access control on notify. For notify messages aimed at a zone that is served, BIND 9.3.2 returns a NOERROR answer, and NSD 3 returns NOTAUTH. For notify messages on a zone that is not served (in-addr.arpa.) BIND 9.3.2 returns NOTAUTH and NSD 3 returns NXDOMAIN. \vspace{-8pt}\subparagraph{Analysis:} Default configuration differs between the two packages. NSD is more strict. Error codes are different, the tools that send notifies are not affected. \subsubsection{n-update - NSD does not implement dynamic update} \label{n-update} For UPDATE, you can get either REFUSED/NXRRSET/other RCODE from BIND 9.3.2 or NOTIMPL from nsd3. \vspace{-8pt}\subparagraph{Analysis:} NSD does not implement dynamic update. \subsubsection{b-mailb - BIND does not implement MAILB} \label{b-mailb} For MAILB, you can get either NOTIMPL(BIND 9) or NOERROR/NXDOMAIN(NSD 3). \vspace{-8pt}\subparagraph{Analysis:} BIND does not implement queries for the MAILB type. NSD treats it as one of the RRTYPEs. MAILB is obsoleted by RFCs, the MX type is used to transfer mail information now. \subsubsection{d-version - BIND returns servfail on version.server queries} \label{d-version} NSD returns version.server query, BIND returns servfail. \vspace{-8pt}\subparagraph{Analysis:} Both NSD and BIND return version.bind queries of the chaos class. These queries differ in the version number they return, of course. BIND does not return version.server queries. This is a design decision on the part of NSD to return version.server queries with the same answer. \subsubsection{d-additional - Different additional section on truncated answers} \label{d-additional} NSD and BIND return different additional sections on truncated answers to queries from the root. These answers are 480+ bytes long. \vspace{-8pt}\subparagraph{Analysis:} Not all the A and AAAA data fits into the additional section of the answer. BIND includes different names than NSD does, and BIND is observed to sometimes include one more AAAA record, less A records in the additional section. Resolvers should be unaffected. \subsubsection{d-refusedquery - BIND includes query section in REFUSED answers} \label{d-refusedquery} BIND includes the query sent for REFUSED answers. NSD replies with only the DNS header section. \vspace{-8pt}\subparagraph{Analysis:} The resolver must inspect the query ID. The error code provides sufficient information. Sending the header makes NSD replies smaller and thus more resilient to DoS attacks. \subsubsection{d-hostname - BIND adds a NS record for hostname.bind} \label{d-hostname} BIND includes an additional RR in the authority section of the reply: \footnotesize \begin{verbatim} hostname.bind. 0 CH NS hostname.bind. \end{verbatim} \normalsize \vspace{-8pt}\subparagraph{Analysis:} The RR seems useless. NSD does not include it. \subsubsection{n-ixfr-notimpl - NSD does not implement IXFR} \label{n-ixfr-notimpl} To queries for IXFR BIND responds with a valid answer (the latest SOA) and NSD responds with NOTIMPL error. \vspace{-8pt}\subparagraph{Analysis:} NSD 3.0.0 does not implement IXFR. It returns NOTIMPL by design. \subsubsection{d-formerrquery - BIND includes query section in FORMERR answers} \label{d-formerrquery} BIND includes the query sent for FORMERR answers. NSD replies with only the DNS header section. For some queries, NSD includes an EDNS record in the reply if there was a recognizable EDNS record in the query. \vspace{-8pt}\subparagraph{Analysis:} The resolver must inspect the query ID. The error code provides sufficient information. Sending the header makes NSD replies smaller and thus more resilient to DoS attacks. \subsubsection{d-badqueryflags - BIND includes query section in FORMERR answers} \label{d-badqueryflags} BIND includes the query section in reply to unparseable queries. NSD does not. \vspace{-8pt}\subparagraph{Analysis:} Same as d-formerrquery (\ref{d-formerrquery}), but the implementation of the comparison software could not parse the query either, thus a separate label. \subsubsection{d-unknown-class - BIND includes query section in answers to unknown class} \label{d-unknown-class} For queries with an unknown class in the query, BIND includes the query section in the answer. NSD does not. \vspace{-8pt}\subparagraph{Analysis:} Same as d-formerrquery (\ref{d-formerrquery}), but for a different error. \subsubsection{d-unknown-opcode - NSD returns NOTIMPL for unknown opcode} \label{d-unknown-opcode} For queries that are bad packets, with malformed RRs, with an unknown opcode, BIND returns a FORMERR, but NSD gives up after checking the opcode and returns NOTIMPL. NSD copies the flags from the query, and turns on the QR (query response) bit, BIND zeroes some of the flags. \vspace{-8pt}\subparagraph{Analysis:} NOTIMPL is appropriate since NSD does not implement whatever functionality is being looked for. \subsubsection{b-upwards-ref - BIND returns root delegation} \label{b-upwards-ref} For queries to a domain that is not served, which can only have arrived at this server due to a lame delegation, BIND returns a root delegation. NSD returns SERVFAIL. \vspace{-8pt}\subparagraph{Analysis:} By design, NSD does not know the root-servers. NSD is unable to reply as the zone is not configured, hence the SERVFAIL. This is also discussed in the REQUIREMENTS document for NSD. \subsubsection{b-noglue-nsquery - BIND returns no glue for NS queries} \label{b-noglue-nsquery} For queries for the NS records of the zone, BIND does not include glue for the NS records. NSD includes glue for the NS servers that lie within the zone. \vspace{-8pt}\subparagraph{Analysis:} The glue saves a followup query. \subsubsection{d-noquestion - different error on no question} \label{d-noquestion} For queries without a question section the error code differs. NSD considers it a FORMERR. BIND returns REFUSED. \vspace{-8pt}\subparagraph{Analysis:} Error code not specified for this corner case. No problems for resolvers. \subsubsection{b-uchar - BIND returns FORMERR on strange characters} \label{b-uchar} BIND returns FORMERR on strange characters in the query, such as 0x00, 0xff, 0xe4, 0x20, 0x40 and so on. \vspace{-8pt}\subparagraph{Analysis:} NSD does not give a formerr on these queries, it processes them. NSD normalizes names to lower case. Otherwise leaves them untouched. BIND preserves case in answers. Choice made in REQUIREMENTS for NSD, also see RFC1035\cite{rfc1035} 2.3.3. \section{Response differences between NSD 2.3.6 and NSD 3.0.0} The differences between NSD 2.3.6 and NSD 3.0.0 are listed below. All are due to version number changes and new features in NSD 3. \subsection{Comparison of responses in root trace} Differences between NSD 2.3.6 and NSD 3.0.0 for a root trace. Note that apart from the 26 packets that are different, all responses are binary the same on the wire between the two versions of NSD. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-notify (\ref{n-notify}) & 19 & 73.08\% \\ n-ixfr (\ref{n-ixfr}) & 3 & 11.54\% \\ version.bind (\ref{nsd-version}) & 3 & 11.54\% \\ version.server (\ref{nsd-version}) & 1 & 3.85\% \\ Total number of differences: & 26 & 100\% \\ Number of packets the same after normalization:&2244590 \\ Number of packets exactly the same on the wire:&2244590 \\ Total number of packets inspected: &2244616 \\ \end{tabular} \subsection{Comparison of responses in NL TLD trace} Differences between NSD 2.3.6 and NSD 3.0.0 for a nl. trace. Note that apart from the 311 packets that are different, all responses are binary the same on the wire between the two versions of NSD. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-notify (\ref{n-notify}) & 289 & 92.93\% \\ version.bind (\ref{nsd-version}) & 22 & 7.07\% \\ Total number of differences: & 311 & 100\% \\ Number of packets the same after normalization:& 99689 \\ Number of packets exactly the same on the wire:& 99689 \\ Total number of packets inspected: &100000 \\ \end{tabular} \subsection{Version number - version.bind and version.server} \label{nsd-version} To queries for version.bind and version.server the different implementations return a different version number, as they should. \vspace{-8pt}\subparagraph{Analysis:} Expected. Correct version numbers are returned. \subsection{n-notify - notify not implemented in NSD 2} \label{n-notify} Notifications are handled differently. NSD 2 returns NOTIMPL error code, while NSD 3 returns NOTAUTH or NXDOMAIN error codes. \vspace{-8pt}\subparagraph{Analysis:} Default config denies all notify queries for NSD 3. These answers are correct for non-existing and not authorized domains. \subsection{n-ixfr - IXFR error FORMERR in NSD 2} \label{n-ixfr} To IXFR query questions different error codes are given. The NSD 2 gives FORMERR (due to the RR in the authority section). NSD 3 returns NOTIMPL. \vspace{-8pt}\subparagraph{Analysis:} Neither version of NSD implements IXFR. It is more appropriate to return the NOTIMPL error code in that case. Bugfix in NSD. \section{Response differences between BIND 8 and NSD 3.0.0} In this section the response differences between BIND 8.4.7 and NSD 3.0.0 are categorized and analyzed. \subsection{Comparison of responses in root trace} The differences between BIND 8.4.7 and NSD 3.0.0 when presented with queries for the root zone are below. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-clrcdbit (\ref{n-clrcdbit}) & 516372 &84.39\% \\ d-hostname (\ref{d-hostname}) & 53431 &8.73\% \\ d-additional (\ref{d-additional}) & 32526 &5.32\% \\ b8-nodata-ttlminup (\ref{b8-nodata-ttlminup}) & 4611 &0.75\% \\ n-update (\ref{n-update}) & 1856 &0.30\% \\ d-version (\ref{d-version}) & 1033 &0.17\% \\ b8-auth-any (\ref{b8-auth-any}) & 519 &0.08\% \\ b8-badedns0 (\ref{b8-badedns0}) & 492 &0.08\% \\ d-unknown-class (\ref{d-unknown-class}) & 482 &0.08\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 451 &0.07\% \\ b-class0 (\ref{b-class0}) & 97 &0.02\% \\ d-notify (\ref{d-notify}) & 18 &0.00\% \\ b8-ignore-tc-query (\ref{b8-ignore-tc-query}) & 6 &0.00\% \\ b8-badquery-ignored (\ref{b8-badquery-ignored}) & 4 &0.00\% \\ n-ixfr-notimpl (\ref{n-ixfr-notimpl}) & 3 &0.00\% \\ b-soattl (\ref{b-soattl}) & 1 &0.00\% \\ Total number of differences: & 611902 &100\% \\ Number of packets the same after normalization:&1632714 \\ Number of packets exactly the same on the wire:& 2299 \\ Total number of packets inspected: &2244616 \\ \end{tabular} \subsection{Comparison of responses in NL TLD trace} The differences between BIND 8.4.7 and NSD 3.0.0 when presented with queries for the .nl zone are below. \begin{tabular}{lrr} {\em difference} & {\em packets} & {\em \%diff} \\ n-clrcdbit (\ref{n-clrcdbit}) & 2857 &33.53\% \\ d-unknown-opcode (\ref{d-unknown-opcode}) & 2692 &31.59\% \\ n-update (\ref{n-update}) & 1283 &15.06\% \\ d-badqueryflags (\ref{d-badqueryflags}) & 841 &9.87\% \\ d-hostname (\ref{d-hostname}) & 531 &6.23\% \\ d-notify (\ref{d-notify}) & 293 &3.44\% \\ d-version (\ref{d-version}) & 22 &0.26\% \\ b-badquery-badanswer (\ref{b-badquery-badanswer}) & 1 &0.01\% \\ b8-badedns0 (\ref{b8-badedns0}) & 1 &0.01\% \\ Total number of differences: &8521 &100\% \\ Number of packets the same after normalization:&91479 \\ Number of packets exactly the same on the wire:&90837 \\ Total number of packets inspected:&100000 \\ \end{tabular} \subsection{b8-nodata-ttlminup - BIND 8 uses minimum TTL from SOA also if bigger} \label{b8-nodata-ttlminup} For NXDOMAIN queries in root-servers.net BIND 8 uses the minimum TTL from the SOA as the TTL of the included SOA RR. However, this minimum TTL is larger than the original TTL of the SOA, both NSD 2.3.6, NSD 3 and BIND 9 use the smaller of those two values as the TTL of the included SOA. \vspace{-8pt}\subparagraph{Analysis:} Bug in BIND 8 solved in BIND 9. \subsection{b8-badquery-ignored - BIND 8 replies normally for some bad queries} \label{b8-badquery-ignored} BIND8 manages to reply for malformed queries. NSD replies with FORMERR. \vspace{-8pt}\subparagraph{Analysis:} The query is bad, formerr is needed. Fixed in BIND9. \subsection{b8-badedns0 - BIND 8 ignores bad EDNS0 queries} \label{b8-badedns0} BIND 8 ignores queries with bad EDNS0 section. It answers the query. NSD replies with FORMERR. \vspace{-8pt}\subparagraph{Analysis:} BIND8 is more liberal in accepting broken EDNS0 records. NSD is not. Changed in BIND 9. \subsection{b8-auth-any - BIND 8 includes an authority section on queries for ANY .} \label{b8-auth-any} BIND8 includes an authority section on queries for class ANY . BIND9 and NSD return an empty authority section. \vspace{-8pt}\subparagraph{Analysis:} Fixed in BIND9. \subsection{b8-ignore-tc-query - BIND 8 ignores the TC bit in queries} \label{b8-ignore-tc-query} BIND responds to queries that have the TC bit set. NSD gives FORMERR. \vspace{-8pt}\subparagraph{Analysis:} This is like the n-tcinquery (\ref{n-tcinquery}), except where BIND9 returns NXDOMAIN, BIND8 returns the query with qr bit set. This is fixed in BIND9. NSD is less liberal in accepting queries, it returns form error on queries with the TC bit set. \bibliographystyle{nlnetlabs} \bibliography{allbib} \end{document} nsd-4.1.26/doc/UPGRADING0000664000175000017500000000730412222561700014037 0ustar wouterwouterUpgrading from NSD 3.x to NSD 4 by Wouter C.A. Wijngaards, NLnetLabs, Jul 2012 This document lists the changes in the upgrade from NSD 3 to NSD 4 systems. (scroll down for the NSD 2.x to NSD 3 upgrade manual). * nsdc is gone. You can control the daemon via kill -HUP and kill -TERM, or you can use nsd-control. * to setup nsd-control you have to run nsd-control-setup (as root) and enable remote-control in the nsd.conf file. It uses SSL to contact the daemon. * the nsd.conf file from NSD3 can be used for NSD4 (defaults for new stuff). * the difffile: setting is no longer used but ignored for backwards compatibility. * zones listed in nsd.conf are served. * the zonelistfile: setting sets the file where zones that are added dynamically (and can be removed dynamically) are stored. * the xfrdir: is used to store temporary zone transfer files. * it is possible to define patterns in the nsd.conf file and use the patterns to give config settings for the zones. * patterns accept the same sort of settings which NSD3-zones did. * you can make super-patterns with the include-pattern: setting * the zonefile: statement creates directories when needed, if they do not exist. In the zonefile: statement you can use %s (and other codes) to use (part of) the name of the zone to generate the pathname of the zonefile. * if there is no zonefile (for slave zones) it is not used. * nsdc rebuild and so on is gone, use nsd-control reload or kill -HUP. * it scans if zonefiles are modified and reads those. * you can also specify a zone by name and have nsd read that file. * if you nsd-control reconfig it rereads the config file for zones. * nsdc patch is not necessary * the database is edited at runtime. * it mmap's the nsd.db file for file I/O, this increases virtual memory usage of NSD with the size of the file. * if you like cronjobs, you could have one to nsd-control write and write slave zones that have changed to their zonefile. * other nsdc commands, reconfig (reread patterns, zones, keys), add a zone, delete a zone, and zone transfer control, statistics. Upgrading from NSD 2.x to NSD 3 by Wouter C.A. Wijngaards, NLnetLabs, Aug 2006 This document lists the changes in the upgrade from NSD 2 to NSD 3 systems. * The nsdc.conf file is gone. * specify the config file to nsdc by using the -c option. * binaries are searched for in the installation bin directory, in the PATH and in the directory of nsdc.sh itself. * other options go into the new nsd.conf file. * The nsd.masters file is gone, replaced by nsd.conf. * Look at nsd.conf.5 manual page to see format. * you can list nsd-commandline-options, zones, masters, slaves, keys. * TSIG support: please list the TSIG keys in nsd.conf, or do this with include: "keys.conf" and provide additional security for that file. * For every zone include lines: zone: name: "example.com" zonefile: "example.com.txt" * For secondary zones include in the zone entry: request-xfr: allow-notify: * For master zones include in the zone entry: provide-xfr: notify: * NSD does not provide IXFR, so for secondaries that connect to NSD use request-xfr: AXFR that will only use AXFR, not IXFR to request zone transfers. * No more need for a cron job to do a nsdc update. * nsd will update automatically all secondary zones from master. * You should never need to do nsdc update or nsdc notify by hand. * You can still use a cronjob to do nsdc patch. nsdc patch moves the zone transfer content from temporary storage to the zone files, recompiles the database and reloads nsd. nsd-4.1.26/doc/NSD-4-features0000664000175000017500000001416312220777004015125 0ustar wouterwouterNSD 4 features By W.C.A. Wijngaards, NLnet Labs, 2012. Migration --------- The old NSD3 config file can be used without changes for NSD4. There are new config statements and some old statements are gone. The nsd.db file has a new format that allows read and write. Thus the nsd.db file needs to be re-created in NSD4 format. This happens when you start NSD4. NSD4 needs write permission on the nsd.db directory for that. If you need to rollback to NSD3, run its zonec to recreate the NSD3 nsd.db file (use nsdc rebuild). The cron job for nsdc patch is no longer needed. It can be removed. If you admire cron jobs, you can have a cron job that does "nsd-control write". This would periodically write the contents of changed zones to their zonefile. nsdc is removed, reload with kill -HUP $pid and use nsd-control. The SIGHUP makes NSD4 check zone file timestamps and reload changed zones. nsd-control reload is the same. SIGTERM stops NSD. You probably want to install and enable some of the new NSD 4 features, such as set up nsd-control and statistics. And you may want to use the new pattern config options. Removed config options ---------------------- difffile: ixfr.db is gone. This setting is no longer applicable, because the ixfr.db file is no longer used. Files are created in /tmp now. The value is ignored by NSD4 if given in nsd.conf. ip4-only and ip6-only: are replaced with more straightforward do-ip4 and do-ip6. They are still accepted in nsd.conf for backwards compatibility. New config options ------------------ zonelistfile: zone.list. This file contains a plain text listing of the dynamically added zones and their pattern. It is read and written by NSD while it is running. xfrdir: /tmp. This directory is used to store temporary zone transfer files. They are stored in a unique subdirectory that has few access permissions. tcp-count: 100. This option already exists in NSD3, but in NSD4 you can increase it above 1024, like 2048, to have higher TCP capacity. remote-control: this is a new section in the config file that configures the nsd-control remote control utility. It is very similar to unbound's remote control configuration. With control-enable: yes you can enable it, it is disabled by default. It is bound to the loopback interface by default. See the manpage or sample config for the list of options, it is possible to set the port number and keyfile paths, and configure it to be accessible from the outside. pattern: these allow you to bundle a set of zone config statements. Then for a zone you can include-pattern: "nameofpattern" to apply those config statements. patterns can also include other patterns. This is needed to allow the user to specify the config statement pattern for a newly added zone. But you can also use it to organise the configuration. zone: These already exist in NSD3 and work similarly. For NSD4, they create a zone, these zones added and removed by a restart or the nsd-control reconfig command. Zones that are dynamically added can also be dynamically removed (with nsd-control addzone and delzone), those zones are in the zones.list file. The zone can have the normal zone config statements, and it can also use include-pattern to apply config statements from a pattern to it. The nsd-control utility ----------------------- You can control the NSD4 daemon with signals, SIGHUP, SIGTERM, if you want. It reloads on SIGHUP and this includes parsing and loading changed zone files. More commands are available via the nsd-control utility. It connects over SSL with the daemon and sends the command to it, and prints the result. To enable nsd-control you have to create the private and public keys with nsd-control-setup, run it as root. Then edit nsd.conf and set remote-control: control-enable: yes in the config file. Then you should be able to use nsd-control, the nsd-control status command is a simple check if everything works. reload [zone] : without a zone name it checks if zone files have changed, if so, loads them. If you specify the zone name (nsd-control reload example.com) it'll load that zone. reconfig : this rereads the nsd.conf file without a restart. Only the zone configuration, and ratelimits are updated from it. Other settings, file paths, chroot location, interfaces and port numbers, cannot be applied and need a restart, during the restart NSD will have the permissions to bind port 53 and chroot again. It adds and removes zones that have been added and removed in the config file, and it also changes zone configurations. log_reopen : also done on SIGHUP, but this controls more exactly that only the logfile is reopened. stats and stats_noreset : print statistics. addzone name pattern : adds a new zone to the running server. If it has a zonefile this file is read in and served. If it is a slave zone, a zone transfer is attempted. delzone name : removes zone. write [zone] : write a zone contents from nsd.db to its zonefile in text format. writes all changed zones, but if you specify a particular zone, it writes that zone only. notify [zone] : for master zones here, send notifies to its slaves. If you specify a name, only that zone, otherwise all master zones. transfer [zone] : for slave zones here, attempt a zone transfer from the masters. If you specify a name, only that zone, otherwise all slave zones. force_transfer [zone] : same as transfer but uses full zone transfer with AXFR and does not perform a serial number check. Statistics ---------- With nsd-control you can get a list of statistics from NSD on demand. This makes it easier to integrate NSD into a statistics collection system. In source/contrib/nsd_munin_ is an example munin plugin. Other features -------------- * Performance increase. * Support a high zone count. * Faster zone transfers. * Add and remove zones without a restart. * Can reread zone configuration from config file without a restart. * Higher TCP service levels, more sockets. * Detect which zone files have changed. * Calculates nsec3-prehash incrementally after IXFR. * Domain tree does not have the small leak of domain nodes. More documentation ------------------ The nsd(8) man page, the nsd.conf(5) man page, the nsd-control(8) man page. nsd-4.1.26/doc/TESTPLAN0000664000175000017500000003556412623035675013776 0ustar wouterwouterTEST PLAN for NSD. By W.C.A. Wijngaards, July 2006, NLnetLabs. 1. Introduction --------------- NSD 3 contains far more features than a typical point release. These features need to be tested and checked to make sure they work well. This document describes a plan to test all the features that have been added to NSD. Regression testing is also very important. The old features must remain working. We have a set of tpkg packages to help with it. And also root-trace speed tests to regression test NSD. The feature tests are to be automated, using tpkg packages where possible. 2. Minor Features ----------------- Some minor features for the test: 2.1. DNAME ---------- DNAME support - there are already extensive DNAME tests. (closed). 2.2. NSEC3 ---------- NSEC3 support - use the perl automated nsec3 test - port to tpkg perhaps. Note NSEC3 hash length byte to be implemented, test against others. Test interoperability of that. A simple zone transfer with Bind. (experimental, no need to test any more). 2.3. NSID --------- Would make a nice nsid.tpkg package. NSID support - run NSD with different NSIDs and queries. a- test NSID with zero length, query with NSID. b- very long length, query with NSID c- 012345678 and query for different things. 1- query OK things. - query error 2- nxdomain, 3- loop, 4- nodata. 5- query error (bad queries, wrong zone) - is NSID present. d- NSID and TSIG. 1- query has OK TSIG 2- query has BAD TSIG 3- query for nxdomain 4- bad query, wrong zone e- configure NSID from config file? - is this possible f- test if NSID in NOTIFY responses. (should there?) ldns-notify and parse result packet for nsid. g- test if NSID in AXFR responses. (should there?) drill axfr and see if nsid in result packets. (experimental, so low priority). (need a way to send NSID enabled queries - no test). 3. Transfers ------------ For the transfers the test are to be done using - NSD as a master(AXFR) in 3.1, or a ldns-ixfr miniserver(IXFR) as a master in 3.2 that serves pre-made ixfr answers. The zone transfer tests can be put in one tpkg by using servers at different ports. The allow- lines are then for localhost, all ports (since the sending process uses ephemeral ports, all must be allowed). The request- lines contain the correct port numbers to send to. 3.1. AXFR --------- 3.1.1. AXFR features -------------------- Setup is a secondary zone which requests to a master. the master zone is updated. Then, the secondary should be informed with the notify: statements. And test if secondary got the same zone as master. By doing axfr from both servers and check if the same, and serial nr. Tests 3.1.1 can be one tpkg. (with serial numbers for SOA, to perform serial rollover). - secondary starts with a zone without content (soa=1) so the zone is only mentioned in the config, the zonefile is empty/nonexist on the slave. Master has a soa and three text records. - axfr an empty zone - only the SOA (soa=2) - axfr a zone with only little data. (soa=3) some NS, MX, A, AAAA records. [NOTE: apparently, due to the linked list mgt in domains (of rrset*) the ordering of rrtypes for a domain is reversed after a zone transfer for NSD, i.e. for query type=any. Ordering within an rrset is preserved. Created fix to ordering, but is slow for many rr types... ] - old zone unsigned, new zone signed. (soa=4) sign with two KSKs and one ZSK. And a prepublished ZSK in the zone. ZSK1: Kexample.com.+005+44537 ZSK2: Kexample.com.+005+03824 (prepublish) KSK1: Kexample.com.+005+53988 KSK2: Kexample.com.+005+25320 (presign) - old zone signed, new zone unsigned. (soa=5) different zone contents, some names are still there, unchanged, some names are there RRs changed, some names there different RRtypes, and some names removed, some names added. www: unchanged (including nsec,rrsig). webmail: mail prio changed. printer: name removed. terms: different RR types, now A type. mail: type TXT added. apex: type DNSKEY, nsec, rrsig removed. newservice, ooo: new names - new zone with nsec3. (soa=6) iter=33 salt=AA44FF11 slave detects NSEC3 settings. - new parameters for nsec3. (soa=7) iter=1078 salt=00998877665544332211AADDCCFF slave detects NSEC3 settings. - new zone no longer uses nsec3. (soa=8) uses nsec. - axfr an empty zone (only the SOA) (soa=9 + a lot for serial wraparound) 2**31 = 2147483648 9 + 2**31 : 2147483657 also tested 9 + 2**31-3 -- works. notify and transfer, zone updated. 9 + 2**31-2 -- works. notify and transfer, zone updated. 9 + 2**31-1 -- notify works, but at transfer time 'serial old'. fixed: works, zone updated. 9 + 2**31 -- notify is ignored, 'serial old'. 9 + 2**31+1 -- notify is ignored, 'serial old'. - axfr wraparound zone, couple txts. (soa=2) serial=2 works after serial=9 + 2**31-2 before. These can be done in order. Test done for AXFR. RRset-type ordering preserve fixed. Serial rollover fixed. Serial printed as unsigned. 3.1.2. Huge xfr - see test tpkg for this. It works already. 3.1.3. AXFR and TSIG Like 3.1.1. but enable tsig. Tested, it works. 3.2. IXFR --------- 3.2.1. IXFR Features -------------------- Setup is a secondary with ldns-mini-ixfr server as a master. (ldns/examples/nsd-test/ldns-testns.c). The mini ixfr server responds with canned replies to a IXFR query. - secondary loaded with only the soa = 1. notified with 10. ixfr server responds with soa=1. (i.e. no update available). - same, ixfr server responds with soa=2, and TC (udp). on tcp connection, it responds with a simple difference package. SOA2 SOA1 SOA2 newTXTA newTXTB SOA2 adds a couple records. - to soa is 3, and this one removes the TXT records, makes a new TXTB record and a TXTC record. test that TXTA domain does not exist NXDOMAIN. test that TXTB is updated. test that TXTC exists. - from 3 to 5, with 4 in between. make a ixfr packet that is 3 .. 4 and 4 .. 5 concatenated without compression, so it means more work for processing. So, in the ixfr packet TXTB is removed from 3, added in 4, removed from 4, added in 5. Also in vs4 a txt5 record is added, which stays around. - from 5 to 7, but this time the redundant work is removed from ixfr packet. - 7 to 8, have one domain name where two RR types exist, A and DNAME. remove one RR type in IXFR then make sure the other type still exists. - 8 to 9, have a name with many different A records. Remove one A record from it. Add another A record to it. Test if the rest is there. [Note: when you delete on RR from an RRset, the ordering of the RRset changes, the contents of the rrset get shuffled (last put in empty slot).] 3.2.2. a huge ixfr. ------------------- create test for it. Should be several MBs worth or data removed, MBs of data that stays the same, and MBs that are added. To make sure that the code can handle multiple packet IXFRs, and the state memory between IXFR packets. - created testns version for multiple packet reply. Small, multiple packets. Test from 3.1. but using multiple packets: one RR per packet. This test also falls over from udp to tcp for ixfr. - This works. The Mbs in size is tested in huge axfr test already. 3.2.3. Test remove domain ------------------------- - is_existing = 0 used to remove a domain. Check and test carefully. - test delete middle name i.e. you have a zone with: c.example.com TXT "x" b.c.example.com TXT "x" a.b.c.example.com TXT "x" and you delete the b.c. record. The b.c becomes empty nonterminal. If you then delete a.b.c. TXT, the b.c becomes NXdomain. [- fixed delete with IXFR for empty nonterminals.] - test delete/add a domain and NXdomain/exist replies. - tested in 3.2.1 already, works. - test delet domain and wildcard replies. - Tested, it works, fix for IXFR that makes empty nonterminals. 3.3. Timeouts ------------- Get zone to expire. Check it does not answer. Start only a secondary server, no master. Set expire timeout short. Timers set as refresh=1 retry=1 expire=10 minimum=10 Provide an update. Check it does answer again. Startup the master server after a while. Transfer should happen within the retry interval. Wait for zone to expire again. Check that. Provide old zone on the master, after expire the slave must transfer it. The above works, old zone is transferred and served. Test that the master says that serial number is OK, in 3.2.1 tests. This test also includes IXFR reply from the master that contains AXFR contents. 3.4. TSIG zone transfers ------------------------ Already TSIG tpkg tests, with transfers TSIG protected, so that is ok. TSIG notifies - test it, create test for it. - notify accepted, nsd->nsd notify by starting master and slave server with tsig keys for a zone, update zone at master. Done in 3.1.3. - notify refused. nsd->nsd notify same but use different secret at one server. Test done. 4. IPC -------- 4.1. deadlocks -------------- Have 100.000 zones, all with short SOA timeouts, expire=1 sec. refresh=10. Expire very quickly. This gives many messages from xfrd to server. Send notifies to the server in a loop from a shell script. Lots of messages the other way around. Provide a master server that will serve all the zones (and say they are ok). then proceed to send queries for the zones to the server and see if you get answers. Wait for an hour and try again. Result, the IPC works okay, but xfrd uses much memory, 16Kb for TSIG regions, per zone. With the 2.5 kb in xfrd almost 20 Kb per zone. For 2G for 100.000. A bit much memory, for the largely unused tsig regions. Fixed, tsig for xfrd uses no preallocated worst case memory use, but only a small footprint. During use this may grow; about 1 K per zone perhaps. About 2.5Kb per secondary zone in xfrd, below 1 Kb for a master zone, that works out for 100.000 secondary zones as 250 Mb for xfrd. Perhaps do also with 100 child servers for the NSD. see if it can keep up and the result if it cannot keep up sending to child servers. Since it has to send for each zone to each child a message, this will take more resources. Tested, it cannot keep up. Child servers operate using old zone status of expired/ok, also the machine load is 100%. Also fixed tsig.other_size to be checked when reading TSIG from network. Due to the length and size, more an incidental test, but can be tpkg-ed. 4.2. IPC FORKS -------------- Infinite loop of reloads on a server. Has 10 child servers. wait. See if it runs out of sockets, file descriptors, etc. incidental test. Tested, with adjusted source that repeats reloads. This puts strain on the reload ipc handshake code. And ipc socket code. It works fine. 5. Random mess test ------------------- Setup 7 servers. In master->intermed->slave, with multiple master(2), intermed(3) and slave(2) servers. TSIGs (different) for everyone. Perhaps also include never respond entries (fake address) in acls. - Load random SOA + random data in servers. Backup the setup so it is repeatable. Let them work out what version to run. - Provide updated zone for a master. See what happens. - Send notifies to the slave servers. - Send notifies to the intermed servers. - Send notifies to the master servers. - Kill some server. Start it again. - Kill some server & delete some file (ixfr.db or xfrd.status). - delete ixfr.db - delete xfrd.status - delete ixfr and xfrd files. - run nsdc patch on a server. - pretend an intermediary was offline for a long time with old zone files and old ixfr.db and xfrd.state(!!) files. and see what happens :-) It should refresh/expire and so based on timers in xfrd.state. Tested: - nsd returns formerr on IXFR queries because of data in NS section. But this is correct, fixed NSD, so it is no longer formerr, but refused / not authorised instead. (or whatever we put in axfr.c). - depending on which server they are asking, servers will use one of the master zones (after expiry time exceeded). If master updated, intermediaries, then slaves update themselves too. - NSD would not start with a corrupt diff file. Now logs error and ignores, fixes, the diff file. 6. Portability test ------------------- Port NSD to as many platforms as possible - local: sparc5(ok), alpha(ok), amd64/OpenBsd(jelte thuis), open=FreeBSD(ok), linuxes(ok), MacOsX(ok), Sunos4(ok). - sf compilefarm for more. - x86-linux2 has ip6 disabled. tests dont work with that. - minix3 if we can get it working (the minix3 setup fails somehow). - would be good to have a test set of tpkg (and tools required) to run after a port-test. A very portable set of tpkgs. OSTYPE: (g)make. autoreconf. (g)indent. -> defaults for * systems. dig 8.3 too old (format of output). Need 9+. however dig/bind is not portable enough. ldns: pcat, pcat-diff, pcat-print. xfr1,2:nsd-ldnsd. pcat-grep.pl manual: md5sum/md5. hping(sudo). long: ldns-testns. Made tests more portable, ran tests on linux, freebsd, Solaris. Full testset run on SPARC/SunOS2.5, and fixed two unaligned memory accesses, all tests succeed now. Full testset runs on Powerpc/MacOSX. 7. CODE REVIEW -------------- Code has already had 1x review by Wouter, some review by Miek. More review (again), Jelte, Wouter. - Do some spots of interest. - perhaps a full review as well. 8. todo-tests ideas ------------------- These would be nice as tpkgs, but perhaps manual tests are needed. 8.1. test combinations of configure options and shells ------------------------------------------------------ " run tests with different shells, aka ==-bug bash 1.1. is too old for [[ in tpkg and tests. Some hosts have awk that puts a space before .pre files in tpkg. Some hosts have bash in /usr/local/bin so tpkg fails on that. run tests with different configure options and combinations of them. Many tests fail with disable-ipv6. implement this in a xen-like environment so that different OSs can be checked. run this daily or only when subversion changes for each test, run our "test-suite" " 8.2. patch file remove ---------------------- rm patch file, check xfrd's behavior. Refetches zones Checked in section transfer_axfr. 8.3. 64 bit ----------- GB 64 bit file size transfers. On alpha so nastiest alignment on 64bit machine. Do transfer of > 4 Gb zone. Needs lots of memory(swap space) and disk space. Not done; no host for test. 8.4. Valgrind ------------- run with valgrind - on two nsds. then do the nsd-nsd, and notify the master to get axfr to happen test, with tsig as well enabled. Done, found one uninit variable. 8.5. Chroot ----------- test chroot and the new files/directories. (And the file/dir not in chroot problem, and if all is OK that it works). Done, default locations for ixfr.db and xfrd.state have full pathnames. 8.6. nsdc --------- In temporary test setup above, test nsdc tool. works. Make sure that if nsdc patch breaks a zone transfer in progress it is reattempted later on. hard to test. 8.7. nsd-patch -------------- nsd-patch - run nsd patch and compare zone files, like AXFR/IXFR tests. Done test axfr run, or test-mess. 8.8. gcov --------- gcov to look at code coverage of the tests. Tests added to improve coverage. nsd-4.1.26/doc/REQUIREMENTS0000664000175000017500000010434112623035675014455 0ustar wouterwouter$Id: REQUIREMENTS 4553 2015-11-18 08:50:05Z wouter $ NSD Requirements and Specifications ______________________________________________________________________ A. Scope. NSD is a complete implementation of an authoritative DNS nameserver. This document describes the basic requirements and specifications for this implementation. B. Requirements B.1. General Requirements These requirements are in order of importance: 1. Conformity to the relevant DNS RFCs If complying with the letter of the RFCs will cause a conflict with high load resilience reasoned trade-offs will be made and documented. 2 Code diversity from other implementations NSD is developed from scratch and does not share code or design with other implementations. 3. Authoritative server only NSD is designed to provide authoritative answers only. There are no facilities for caching or recursion. 4. Open source The code will be open source after the first public release. 5. Regression tested against bind8/9 Extensive regression tests with real trace data and synthetic exceptional data will be carried out. For the real traces any differences with bind8/9 will be documented. Should there be substantial differences a bind8/9 compatibility option will be considered. The testing tools will be published separately as much as possible. 6. Resilience to high load As many as UDP queries answered as possible per time interval. Aware of useless queries and limiting answers to conserve output bandwidth. This may supersede strict RFC compliance. Mitigation of DDoS attacks as far as feasible. 7. Documentation The implementation will be well documented with the aim of allowing others to understand its operation in order to be able to maintain the code. This includes these requirements, a general design document and well documented code. 8. Reviewed code All code will be reviewed by at least two persons other than the primary author before being included in a release version. 9. Simplicity NSD will not do things that are not strictly necessary for its task: authoritative name serving. If in doubt a feature is more likely not to be included. The code strives to be as simple and straightforward as possible, even if it looks stupid ;-). 10. Reasonable Portability Should be reasonably portable across hardware architectures and OS platforms. Rough targets: (Intel/SPARC/Alpha)(FreeBSD,Linux,Solaris) 11. Maintenance for initial period NLnet Labs and the RIPE NCC will support NSD for at least 12 months after publication. B.2. Explicit NON-Requirements 1. No caching NSD will not provide cached or recursive answers. 2. No slavish responsiveness NSD may decide to limit answers to queries it considers malicious or useless if this enables it to provide better service to queries it considers valid. Conserving output bandwidth is a consideration. 3. No end-user friendliness NSD operators are considered to have basic Unix and networking knowledge and are also considered to be able to read and understand reasonably written user documentation. 4. No creeping featurism NSD will not implement any functionality that is not strictly necessary for the task of authoritative name serving. Examples: round robin sequence of RRset members in consecutive answers, Also no dynamic plugins. C. Technical Specification. C.0 Environment The server runs with the least possible permissions. NSD will not implement special VM work-arounds to accommodate zones larger than order 10 million RRs in 32-bit address space machines. Operators requiring huge-zone support can use 64-bit machines. C.1. Zone file format and RR records. Zone file format as specified in rfc1035 (5.1), including the $TTL entry for default TTL as in RFC2308 (4) and the binary label format as in RFC2673. We implement most RRs currently assigned by IANA (http://www.iana.org/assignments/dns-parameters) except for RRs that are obsoleted by IANA or assigned experimental, those MAY not be implemented. See below and/or release notes. Zone file MUST not contain errors. i.e. the zonecompiler may fail or produce unpredictable results when: - RRs that are obsolete and not implemented are encountered. - Syntax errors are found (RFC1035 5.2) + not all RRs are of the same zone + not exactly one SOA RR is present at the top of the zone. + delegations are present but required glue is not present. + Out of Zone, non-glue data is encountered. + not all RRs in a RRset have the same TTL (RFC2181 5.2) + if a DNAME exists at node N there may not be any other data at 'N' (except CNAME or DNAME) and there MUST not be any other data at subnodes of 'N' (RFC 2672 section 3). - The default minimum TTL is not specified by the $TTL directive Zones that are parsed by the zonecompiler will be served by the nsd daemon. Only zone files of CLASS "IN" are supported. The zone file parser sets the TTL of those RRs that do not have their TTL defined to the minimum TTL as defined by the $TTL directive unless the RR is part of a RRset and the TTL is set for one of the RRs in the RRset. Parsing of the names in zone files is case insensitive (Note: RFC1035 2.3.3 also see 1034 3.1 "The basic rule is that case can be discarded only when data is used to define structure in a database, and two names are identical when compared in a case insensitive manner." ) The database relies on case; all names will be parsed to lower case. Case of dnames in RDATA will be preserved except for dnames for which dname compression in RDATA is allowed, those dname fields are converted to lower case. (for that subset of RRs compression has preference over case preservation). Also see Appendix B for dname compression in RDATA. DNSSEC consideration (as of 2.0.0): DNSSEC processing of data in a zone will only take place if that zone is marked to be secure. A zone is marked secure if the SOA record is signed. The zone data is not cryptographically checked at the time the zone db is generated; NSD always clears the AD flag on answering data from a secure zone in the database. NSD always copies the CD bit from the query to the response. NSD does not include the DNSKEY RRset in the additional section on queries for the SOA or NS records at the zone apex. It is not clear whether including the DNSKEY RRset is advantageous and not doing so simplifies NSD. C.2. Server and connection management. The server listens on port 53. The server answers with the same IP address and port (53) as the queries has been sent to. Replies are sent to the address/port the queries originated from. (rfc 2181 4) UDP. The server is optimized to handle UDP queries. Large packet sizes are supported. The size is set by the OS (e.g. net.inet.udp.maxdgram on FreeBSD). TCP. The server accepts TCP connections. Note that there may be one or more DNS messages in the stream. Each message is prepended with a 2 byte size (rfc 1035 4.2.2) Connection management (rfc1035 4.2.2.) + the server should not block other activities waiting for TCP data + The server should assume that the client will initiate connection closing and should delay closing its end of the connection until all outstanding client requests have been satisfied. + For closing dormant connections the timeout should be in the order of 2 minutes. NSD specific: + The maximum number of open TCP connections is configurable. It is assumed the OS copes with attacks on the TCP stack (e.g like SYN attacks) C.3 Incoming DNS Message processing. NSD specific choices. These issues are not addressed in the RFCs. Behavior is defined below. + Non parsable messages are replied to with a FORMERR. + Each UDP packet only carries one DNS Message. Any data behind the DNS message is considered garbage and is ignored. + Incoming DNS messages with the QR bit set to 1 (response) are discarded. (In spirit of rfc 1035 sect 7.3) + RD is copied into the response (rfc 1035 4.1.1) the RA bit is set to 0 and the QUERYID is copied into the response message. + OPCODE 0 (QUERY) results in normal handling of packet (rfc1035) OPCODE 1 (IQUERY) results in RCODE=4 NOTIMPL (rfc1035) OPCODE 2 (STATUS) results in RCODE=4 NOTIMPL (rfc1035) OPCODE 3 (RESERVED) results in RCODE=4 NOTIMPL OPCODE 4 (NOTIFY) results in RCODE=4 access control list processing and then handling of the notify. (rfc1995) OPCODE 5 (UPDATE) results in RCODE=4 NOTIMPL (rfc2136 sect 3) + AA bit in query packet is ignored. + TC bit set in a query packet is answered with FORMERR. [This must always be a broken implementation since the max length of the name is 255 octets.] + RCODES are ignored. + QDCOUNT=1 results in further processing. QDCOUNT!=1 results in RCODE=1 FORMERR + QCLASS=IN results in further processing. + QCLASS=ANY results in further processing with the AA bit in the response off (rfc 1035 6.2) + QLASS=CHAOS only leads to further processing if the queries are for the names ID.SERVER or VERSION.SERVER. Any other query in that namespace will lead to RCODE=REFUSED. For QTYPE other than TXT a NOERROR with a trivial SOA RR in the AUTHORITY section will be returned. Behavior for QTYPE=TXT is defined in draft-ietf-dnsop-serverid-00.txt + QCLASS!=IN && QCLASS!=ANY && QCLASS!=CHAOS results in RCODE=REFUSED [Background: BIND8 generates a SERVFAIL but I would say that a A NOERROR message with empty Answer, Authority and Additional section is also a good answer and more in the spirit of RFC 1034 section 4.3.1. We choose to mimic the behavior of bind. BIND9 generates a status RCODE=5 REFUSED. ] + Other sections should be empty otherwise FORMERR. + except, EDNS and TSIG opt records are allowed. + TSIG signature is checked, otherwise a TSIG error. + Presence of OPT RR indicates support of EDNS (rfc2671). If the VERSION > 0 then the server will respond with an OPT with RCODE=BADVERSION and VERSION=0 (The server supports EDNS0) In further processing ENDS0 support is taken into account. + If the DNSSEC OK bit (DO bit) is set then the query will be processed as a DNSSEC request. Although RFC3225 does not explicitly specify this NSD clears the DO bit in the answer. C 4 Further Query processing. Preconditions: + the QCLASS is either IN or ANY. For both classes the IN class zones are searched in the same manner. The difference in the response will be in the Authority information. + It is known if the requester supports EDNS0 + There is only one query in the DNS message to be answered. + The RD & message ID of the incoming query has been copied into the response message. + It is known if the requester wants DNSSEC processing as indicated by the DO bit being set. C 4.1 Actions based on QTYPE of incoming Query. If QTYPE>=249 we are dealing with special queries. case QTYPE=TKEY case QTYPE=TSIG case QTYPE=IXFR respond with RCODE=5 (REFUSED) case QTYPE=AXFR respond with AXFR (TSIG is supported) case QTYPE=MAILB proceed with processing. case QTYPE=MAILA proceed with processing. case QTYPE=ANY proceed with processing. QTYPE < 249 process the query Further processing of the packet is based on the algorithm from 1034 as modified by (rfc2672 4). Below is the algorithm as applies to an authoritative cache-less server and with the preconditions from above. We have also included DNSSEC considerations (rfc2535 and rfc3225) The first versions of NSD will not have DNSSEC processing implemented. (Read this as the DO bit is not set). 1. Search the available zones for the zone which is the nearest ancestor to QNAME. If such a zone is found, go to step 2, otherwise step 3. 2. Start matching down, label by label, in the zone. The matching process can terminate several ways: a. If the whole of QNAME is matched, we have found the node. If the data at the node is a CNAME, and QTYPE doesn't match CNAME, copy the CNAME RR into the answer section of the response, change QNAME to the canonical name in the CNAME RR, and go back to step 1. If the DO bit is set in the query the RRSIG(CNAME) needs to be copied in the answer section as well. Otherwise, copy all RRs which match QTYPE into the answer section. Also copy corresponding RRSIGs into the answer section if the DO bit was set, goto step 4. If QTYPE is 'ANY' copy all RRs including the security related RR types regardless if the DO bit was set into the answer section. If none of the RRtypes matched QTYPE, the DO bit was set and the zone is marked secure then the answer section is left empty and b. If a match would take us out of the authoritative data, we have a referral. This happens when we encounter a node with NS RRs marking cuts along the bottom of a zone. Copy the NS RRs for the subzone into the authority section of the reply. If the DO bit has been set then if the zone is marked secure then if there is a NSEC record or DS record then include the DS bit and associated RRSIG(DS) into the authority section if the DS record is present for this delegation. If there is no DS record present for this delegation then include the NSEC record with the corresponding RRSIG(NSEC) in the authority section. else we are in an opt-in part of the zone and we should include the the NSEC RR of the last secured RR in the zone and the corresponding RRSIG(NSEC) into the authority section of the answer. fi fi Put whatever addresses are available into the additional section, using glue RRs if the addresses are not available from authoritative data. If the DO bit was set then also copy the RRSIGs for the addresses for which the server is authoritative. Go to step 4. c. If at some label, a match is impossible (i.e., the corresponding label does not exist), look to see whether the last label matched has a DNAME record. BEGIN DNAME (supported as of NSD 3.0) If a DNAME record exists at that point, copy that record into the answer section, if the DO bit is set also copy the RRSIG. If substitution of its for its in QNAME would overflow the legal size for a , set RCODE to YXDOMAIN [DNSUPD] and exit; otherwise perform the substitution and continue. If the query was not extended [EDNS0] with a Version indicating understanding of the DNAME record, the server SHOULD synthesize a CNAME record as described above and include it in the answer section. Go back to step 1. Note that there should be no descendants of a DNAME in the same zone (rfc2672 3). So if a DNAME has been found only go to step 1 if another zone can be found. NSD will refuse to zonecompile a zone that has descendants of a DNAME. It always synthesizes CNAME records. END DNAME If there was no DNAME record, look to see if the "*" label exists. If the "*" label does not exist, check whether the name we are looking for is the original QNAME in the query or a name we have followed due to a CNAME. If the name is original, set an authoritative name error (RCODE=3 NXDOMAIN) in the response, if the DO bit was set then include the appropriate NSEC records (see section 4.5.) in the authority section, then exit. If the "*" label does exist, match RRs at that node against QTYPE. If any match, copy them into the answer section, but set the owner of the RR to be QNAME, and not the node with the "*" label. If the DO bit is set copy the RRSIG for the * label and matching QTYPE also set the owner of the RRSIG RR to be QNAME). In addition a NSEC record indicating that no specific matches are possible should be returned in the additional section. Otherwise just exit. Go to step 4. 3. If a there was no delegation of authoritative data return the root delegation in the authority section and continue with 4. Also see Appendix B.1 4. Using local data only, attempt to add other RRs which may be useful to the additional section of the query if the DO bit was set in the query then for retrieval of SOA or NS a DNSKEY of the same name should be added. For retrieval of type A, AAAA or A6 RRs the DNSKEY should also be included. See section 4.2 as well. Note that on a QNAME match the NS records are not copied into the AUTH section (This is a requirement from step 4 'matching down the cache' from rfc1034 4.3.2). This is a requirement only for caching servers. BIND8 will copy the the NS in the Auth section for authoritative server too. C 4.2 Additional Data processing. Additional data is added as long as there is space in the packet. When processing the additional section priority is (rfc 2535 3.5 and rfc 2874 4) + A + A6 + AAAA + DNSKEY For truncation see section C.4.4 If the DO bit is set RRSIGs will be included with the additional data. Although not specified in the RFCs we will assume the following priority: Note that A glue is always added before any AAAA glue. + A + RRSIG A + A6 + RRSIG A6 + AAAA + RRSIG AAAA + DNSKEY + RRSIG DNSKEY NSD will act as being authoritative for one zone without having the other zones in cache. In other words: If a NSD is authoritative for say both ripe.net and nlnetlabs.nl and both these zones are secondary for each others NS. Then, at least with my zone parser a query for ripe.net NS would return ANSWER: ripe.net NS ns.ripe.net NS ns.nlnetlabs.nl Additional ns.ripe.net A 10.0.0.1 and not ANSWER: ripe.net NS ns.ripe.net NS ns.nlnetlabs.nl Additional ns.ripe.net A 10.1.0.1 ns.nlnetlabs.nl A 10.2.0.2 This behavior is a consequence of NSD using precompiled packets. These are 'constructed' zone by zone. It is an optimisation of speed versus network optimisation. In NSD2 and later this behaviour still exists, even though the packets are constructed at run time, only information from the current zone is added to a response. C 4.3 Label compression in RDATA In the spirit of RFC 1035 section 3.3. and 4.4.1 ("Pointers can only be used for occurrences of a domain name where the format is not class specific.") we only do label compression for labels in rdata for which this is specifically mentioned in the RFC defining the RR. -NS, SOA, CNAME, and PTR (rfc 1035 3.3) Others defined in (rfc 1035 3.3) are not compressed. BIND8 does compression for all RR from rfc 1035 for which dnames appear in the rdata. (Note that other RFCs do refer to e.g. MX dname in rdata being compressed (e.g. rfc2974 4.). -MB, MG, MR, MINFO, MX also have compressed dnames. These RRs and their compression are described in RFC 883. -NSEC, RRSIG and DNSKEY MUST NOT have dname compression (rfc 4034). For RRs not mentioned here no label compression in the rdata is performed. C 4.4 Truncation handling. (as rfc2181 9) If inclusion of a RR set that is REQUIRED in either the answer or authority section leads to message truncation. The section is left empty and the truncation (TC) bit is set. If the DO bit is set RRSIG RRs are required in the answer and authority section. Inclusion of NS RRs in the authority section when QTYPE=DNSKEY is removed since NSD version 3.2.3. QTYPE=DS followed in version 3.2.7. This is to prevent resolvers from unnecessarily falling back to TCP. Only DNSKEY and DS records are considered, because it showed that especially these DNS packets are 'troublesome'. The feature 'minimize responses' is included since NSD 3.2.9. NS RRsets that would go into the Authority section in positive responses are not considered REQUIRED and therefore will NOT lead to setting of the TC bit. The minimal response size is: - 512 in case of no EDNS; - 1480 in case of EDNS/IPv4; - 1220 in case of EDNS/IPv6; - the advertized buffer size if that value is smaller than the the EDNS defaults. The feature can be disabled during build time with --disable-minimal-responses. If inclusion of an RRset in the Additional section is not possible RRs are omitted one by one. This may lead to incomplete RRsets. Omission of RRs from the Additional section because of message size constraints will NOT lead to setting of the TC bit. (rfc2181 9) We allow for incomplete RRsets in the additional section. C 4.5 NSEC processing. The NSEC record is required to be in the authority section if a QNAME or a QTYPE cannot be matched (see section 5 or RFC2535). If the DO bit on the query is not set then NSEC records should only be required if QNAME and QTYPE match. If the do bit on the query is set then we have to do NSEC processing if a zone is marked as secure otherwise we should do nothing. If the QNAME matches a name in the zone but the QTYPE does not match then the answer section should remain empty and the Authority section should have either the NSEC RR that matches QNAME or the NSEC RR (opt-in) that indicates QNAME is in an insecure part of the zone. C 4.6 Timeout management. NSD manages timeouts on the SOAs for secondary zones according to RFC. Timeouts are randomized, to avoid network bursts. The randomization used is 90-100% of the original value - meaning that it can never be delayed. This means zones cannot expire later than they should. It does mean the average timeout becomes 95% of the original. The random number calculation is primitive but fast. It is about spreading load not about randomness per se (in the crypto sense). ------------------------------------------------------------------------------- Appendix A IANA list of RR records RR records details. "A" 1, # RFC 1035, Section 3.4.1 No additional processing "NS" 2, # RFC 1035, Section 3.3.11 Additional A type processing. dname compression in RDATA "MD" 3, # RFC 1035, Section 3.3.4 (obsolete) "MF" 4, # RFC 1035, Section 3.3.5 (obsolete) "CNAME" 5, # RFC 1035, Section 3.3.1 No additional section processing. dname compression in RDATA "SOA" 6, # RFC 1035, Section 3.3.13 No additional section processing. SOA TTL semantics updated by rfc2308 dname compression in RDATA "MB" 7, # RFC 1035, Section 3.3.3 Additional processing type A of MADNAME "MG" 8, # RFC 1035, Section 3.3.6 No additional section processing. "MR" 9, # RFC 1035, Section 3.3.8 No additional section processing. "NULL" 10, # RFC 1035, Section 3.3.10 NOT IMPLEMENTED Not allowed in master files. (Not implemented in BIND) "WKS" 11, # RFC 1035, Section 3.4.2 (deprecated in favor of MX [RFC-1123] but not Obsolete) "PTR" 12, # RFC 1035, Section 3.3.12 No additional section processing. dname compression in RDATA "HINFO" 13, # RFC 1035, Section 3.3.2 No additional section processing. "MINFO" 14, # RFC 1035, Section 3.3.7 No additional section processing. "MX" 15, # RFC 1035, Section 3.3.9 Additional section processing type A of host in Exchange "TXT" 16, # RFC 1035, Section 3.3.14 No additional section processing. "RP" 17, # RFC 1183, Section 2.2 No additional section processing. "AFSDB" 18, # RFC 1183, Section 1 type A additional section processing for dname compression for hostname "X25" 19, # RFC 1183, Section 3.1 No additional section processing. "ISDN" 20, # RFC 1183, Section 3.2 No additional section processing. "RT" 21, # RFC 1183, Section 3.3 type X25, ISDN, and A additional section processing for . dname compression for intermediate-host. "NSAP" 22, # RFC 1706, Section 5 No additional section processing. NSAP requires special parsing rules. "NSAP_PTR" 23, # RFC 1348 (obsolete) "SIG" 24, # RFC 2535, Section 4.1.7: signers name field MAY be compressed. 4.1.8.1: SIG(0) specification. See section 4.2 for additional section processing. SIG signers name field MAY be compressed. (2535 4.1.7) "KEY" 25, # RFC 2535, Section See section RFC 2535 3.5 on inclusion of keys. "PX" 26, # RFC 2163, section 4 says: PX records cause no additional section processing All normal DNS conventions, like default values, wildcards, abbreviations and message compression, apply also for all the components of the PX RR. Compression is not explicitly mentioned: This label is CLASS specific: NO compression. "GPOS" 27, # RFC 1712 (obsolete) "AAAA" 28, # RFC 1886, Section 2.1 "LOC" 29, # RFC 1876 No requirements on additional section processing. "NXT" 30, # RFC 2535 No requirements on additional section processing. NXT dname field MAY be compressed. (2535 4.2) "EID" 31, # draft-ietf-nimrod-dns-xx.txt e.g. http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt "NIMLOC" 32, # draft-ietf-nimrod-dns-xx.txt e.g. http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt "SRV" 33, # RFC 2782 No dname compression of target field. (rfc2782 page 4) "ATMA" 34, # [Dobrowski] "NAPTR" 35, # RFC 2168, 2915 Contains regular expressions. Take care of escaping backslashes while parsing (rfc2915 p6): 'Replacement' field: no compression "KX" 36, # RFC 2230 KX records MUST cause type A additional section processing for the host specified by EXCHANGER. In the event that the host processing the DNS transaction supports IPv6, KX records MUST also cause type AAAA additional section processing. The KX RDATA field MUST NOT be compressed. (rfc2230 section 3) "CERT" 37, # RFC 2538 No dnames in rdata "A6" 38, # RFC 2874 No dnames in rdata "DNAME" 39, # RFC 2672 NO dname compression of target field. (rfc2672 sect 3) "SINK" 40, # [Eastlake] "OPT" 41, # RFC 2671 Pseudo RR. Not in zone files. "APL" 42 # RFC 3123 An APL RR with empty RDATA is valid and implements an empty list. "DS" 43, # RFC 4033, 4034, 4035. Included with referrals. "SSHFP" 44, # SSH Key Fingerprint, RFC 4255 "IPSECKEY" 45, # RFC 4025 Public key RSA/DSA for use in IPSEC. "RRSIG" 46, # RFC 4033, 4034, 4035. RFC 3755. Signature, uncompressed dnames. "NSEC" 47, # RFC 4033, 4034, 4035. RFC 3755. Signed next ownername, to disprove rrset types and domain name existence. Uncompressed dnames. "DNSKEY" 48, # RFC 4033, 4034, 4035. RFC 3755. Key for zone signing or key signing. Public key part. "DHCID" 49, # draft-ietf-dnsext-dhcid-rr-13.txt "NSEC3" 50, # RFC 5155. "NSEC3PARAM" 51, # RFC 5155. "TLSA" 52, # RFC 6698. Unknown 53 - 98, "SPF" 99, # RFC 4408 (Experimental). "UINFO" 100, # [IANA-Reserved] "UID" 101, # [IANA-Reserved] "GID" 102, # [IANA-Reserved] "UNSPEC" 103, # [IANA-Reserved] "NID" 104, # RFC 6742 "L32" 105, # RFC 6742 "L64" 106, # RFC 6742 "LP" 107, # RFC 6742 "EUI48" 108, # RFC 7043 "EUI64" 109, # RFC 7043 "TKEY" 249, # RFC 2930 "TSIG" 250, # RFC 2845 "IXFR" 251, # RFC 1995 "AXFR" 252, # RFC 1035 "MAILB" 253, # RFC 1035 (MB, MG, MR) "MAILA" 254, # RFC 1035 (obsolete - see MX) "ANY" 255, # RFC 1035 "URI" 256, # RFC 7553 "CAA" 257, # RFC 6844 ______________________________________________________________________ Appendix B Details on specific design and implementation choices. B.1. Returning the root delegation when no answer can be found From RFC1034/1035 it is not obvious if returning a root delegation is a (non-)requirement for authoritative servers. We have decided not to implement a root-hints since an authoritative server should in normal circumstances only receive queries for which the server is authoritative. Also see RFC 1123 section 6.1.2.5. Whenever an answer cannot been provided we return a SERVFAIL. It has been argued that this is a policy decision and thus a REFUSE should be returned. However, in the spirit of RFC1034/1035 a server should return cached data, if that cache cannot be reached a SERVFAIL is an appropriate response. Also see the discussion on the 'namedroppers list' Starting April 2002 with subject "name server without root cache " (ftp://ops.ietf.org/pub/lists/) ______________________________________________________________________ Appendix C (Planned) Features NSD Version 1.0.0. and above The first release ( 1.0.0 ) contains an implementation of the standard RFC 1034 and RFC 1035, of proposed standards RFC2181 (clarifications), RFC2308 (negative caching). AXFR is not implemented in v1.0.0. The RRs specified in the following RFCs are implemented in v1.0.0 - RFC 1183 (Multiple RRs) - RFC 1706 (NSAP) (Informational) - RFC 1876 (LOC RR) - RFC 1886 (AAAA RR) - RFC 2230 (KX RR) (Informational) - RFC 2536 (CERT RR) - RFC 2671 (EDNS0) - RFC 2782 (SRV) - RFC 2915 (NAPTR RR) - RFC 2915 (SRV RR) - Version 1.0.1 will also support features from draft-ietf-dnsop-serverid-00.txt: The following names have associated TXT RRs in the CHAOS class: ID.SERVER. and VERSION.SERVER. - RFC2535 (DNSSEC) will be implemented in (1.1.0) once the current drafts DS and OPT-IN have made it to the standards track. (DNSSEC also includes RFC2536 (DSA), RFC2537 (RSA), RFC3225 (DO bit) Version 1.1.0 will not allow wildcards in DNSEC signed zones. NSD Version 2.0. and above - AXFR will be implemented in 1.0.1 with simple IP based ACLs. In 1.1.0. AXFR will also supported with RFC 2845 (TSIG) Using external tool nsd-xfer, that supports TSIG to download a zone from a server. - DNSSEC supported RRSIG/NSEC/DNSKEY, RFC 4033, 4034, 4035. - wildcards allowed in dnssec secured zones. - RFC 2673 (Binary labels) - RFC 2874 (A6) NSD Version 3.0. and above AXFR: - NSD serves AXFR, with TSIG if needed. - NSD requests AXFR from xfrd. This is noncompliant with RFC. It does not ask for the SOA serial number using a query beforehand (nsd-xfer does). It terminates the AXFR after the first packet if it determines the AXFR is not needed. RFC 1995 (IXFR) support only for making requests to other servers. - IXFR is not served. RFC 1996 (NOTIFY): - will ignore extraneous data in notify (instead of checking if they differ from content in zone). Only checks SOA serial. This is too hard, since other information is not available in xfrd, the process that handles the notify. - Will not send notify to NS-servers of a zone. Only notify sent to 'notify:' entries in config file. - Incoming has an ip-based and key-based access control list. - can be with TSIG. RFC 2845 (TSIG): - TSIG is supported for notify, axfr, ixfr, regular queries. RFC 2672 (DNAME) support. Secondary zones: - follows SOA timers. (NSD 2 and before did not) (RFC 1034, 1035). RFC 4509 (SHA-256 DS) support. RFC 4635 (HMAC SHA TSIG) support for mandatory algorithms: hmac-md5, hmac-sha1, hmac-sha256. RFC 5001 (NSID) support. RFC 5155 (NSEC3) support. RFC 5702 (SHA-2) support. RFC 5936 (AXFR) support. RFC 6605 (ECDSA) support. RFC 6698 (DANE) support for TLSA RR type. RFC 6742 (ILNP) support for NID, L32, L64, LP RR types. RFC 6844 (CAA) support for CAA RR type. RFC 7043 (EUI48+64) support for EUI48, EUI64 RR types. RFC 7553 support for URI RR type. Not implemented: RFC2136 (Dynamic update) are not implemented and will not be implemented as zone control is not implemented in NSD itself. Appendix D. Changes to this file. 14 january 2014 (Matthijs Mekking) - Updated file with CAA RRtype support. 18 june 2013 (Matthijs Mekking). - Updated file with EUI48 and EUI64 RRtype support. 25 april 2013 (Matthijs Mekking). - Removed requirements label compression for RP, RT and AFSDB. 19 november 2012 (Matthijs Mekking). - Updated file with RFC 6698 (DANE) support for TLSA RR type and RFC 6742 (ILNP) support for NID, L32, L64, LP RR types. 17 april 2012 (Matthijs Mekking). - Updated file with RFC 5936 (AXFR) and RFC 6605 (ECDSA) support. 17 october 2011 (Matthijs Mekking). - Updated file with RFC 5702 (SHA-2) and RFC 4509 (SHA-256 DS) support. 17 october 2011 (Matthijs Mekking). - Added section on minimal responses. 24 february 2010 (Matthijs Mekking). - Updated file with RFC 5001 (NSID) and RFC 5155 (NSEC3) support (version 3.0.0 and above). 30 october 2008 (Matthijs Mekking). - Added support for RFC 4635 (HMAC SHA TSIG). 26 july 2006 (Wouter Wijngaards). - Comments changed to background items. - KEY->DNSKEY, SIG->RRSIG in the text, dnssec-bis style. ______________________________________________________________________ $Id: REQUIREMENTS 4553 2015-11-18 08:50:05Z wouter $ nsd-4.1.26/doc/README.icc0000664000175000017500000000144610443534063014217 0ustar wouterwouterCompiling with the Intel C Compiler (ICC) version 7.0. Configure NSD to use ICC. $ CC=icc ./configure [configure-options] Then everything should compile (just ignore the warnings), except on RedHat 8.0. This is due to a bug in the GNU C library used. This bug may apply to other Linux distributions or systems using the GNU C library. To compile NSD with the ICC compiler on RedHat 8.0 you need to patch the file /usr/include/bits/byteswap.h. The following patch should work: --- byteswap.h.orig 2003-02-26 13:59:41.000000000 +0100 +++ byteswap.h 2003-02-26 13:59:57.000000000 +0100 @@ -81,7 +81,7 @@ __v; })) # endif #else -# define __bswap_16(x) \ +# define __bswap_32(x) \ (__extension__ \ ({ register unsigned int __x = (x); __bswap_constant_32 (__x); })) #endif nsd-4.1.26/doc/RELNOTES0000664000175000017500000021306713377730333013773 0ustar wouterwouterNSD RELEASE NOTES 4.1.26 ================ FEATURES: - DNSTAP support for NSD, --enable-dnstap and then config in nsd.conf. - Support SO_REUSEPORT_LB in FreeBSD 12 with the reuseport: yes option in nsd.conf. - Added nsd-control changezone. nsd-control changezone name pattern allows the change of a zone pattern option without downtime for the zone, in one operation. BUG FIXES: - Fix #4194: Zone file parser derailed by non-FQDN names in RHS of DNSSEC RRs. - Fix #4202: nsd-control delzone incorrect exit code on error. - Tab style fix to use tab for 8 spaces, from Xiaobo Liu. - Fix #4205: enable-recvmmsg in mixed IPv4/IPv6 environment fails. This sets the msg_hdr.msg_namelen correctly after receipt. - Fix to not set GLOB_NOSORT so the nsd.conf include: files are sorted and in a predictable order. - Fix #3433: document that reconfig does not change per-zone stats. 4.1.25 ================ FEATURES: - nsd-control prints neater errors for file failures. BUG FIXES: - Fix that nsec3 precompile deletion happens before the RRs of the zone are deleted. - Fix printout of accepted remote control connection for unix sockets. - Fix use_systemd typo/leftover in remote.c. - Fix codingstyle in nsd-checkconf.c in patch from Sharp Liu. - append_trailing_slash has one implementation and is not repeated differently. - Fix coding style in nsd.c - Fix to combine the same error function into one, from Xiaobo Liu. - Fix initialisation in remote.c. - please clang analyzer and fix parse of IPSECKEY with bad gateway. - Fix nsd-checkconf fail on bad zone name. - Annotate exit functions with noreturn. - Remove unused if clause during server service startup. - Fix #4156: Fix systemd service manager state change notification When it is compiled, systemd readiness signalling is enabled. The option in nsd.conf is not used, it is ignored when read. 4.1.24 ================ FEATURES: - #4102: control interface via local socket. configure it with control-interface: "/path/nsd.ctl" The path has to start with a / to separate it from an IP address. The local socket does not use SSL, but unencrypted traffic, use file and containing directory permissions to restrict access. - configure --enable-systemd (needs pkg-config and libsystemd) can be used to then use-systemd: yes in nsd.conf and have readiness signalling with systemd. - RFC8162 support, for record type SMIMEA. BUG FIXES: - Patch to fix openwrt for mac os build darwin detection in configure. - Fix that first control-interface determines if TLS is used. Warn when IP address interfaces are used without TLS. - #4106: Fix that stats printed from nsd-control are recast from unsigned long to unsigned (remote.c). - Fix that type CAA (and URI) in the zone file can contain dots when not in quotes. - #4133: Fix that when IXFR contains a zone with broken NSEC3PARAM chain, NSD leniently attempts to find a working NSEC3PARAM. 4.1.23 ================ BUG FIXES: - Fix NSD time sensitive TSIG compare vulnerability. 4.1.22 ================ FEATURES: - refuse-any sends truncation (+TC) in reply to ANY queries over UDP, and allows TCP queries like normal. - Use accept4 to speed up answer of TCP queries, on Linux, FreeBSD and OpenBSD. BUG FIXES: - Fix nsec3 hash of parent and child co-hosted nsec3 enabled zones. - Fix to use same condition for nsec3 hash allocation and free. 4.1.21 ================ FEATURES: - --enable-memclean cleans up memory for use with memory checkers, eg. valgrind. - refuse-any nsd.conf option that refuses queries of type ANY. - lower memory usage for tcp connections, so tcp-count can be higher. BUG FIXES: - Fix unused variable warnings and uninit variable in statistics printout from clang analyzer. - Fix spelling error in xfr-inspect. - Fix #3562: explain build error when flex missing. - Fix buffer size warnings from compiler on filename lengths. - Fix #4093: Release notes not using 2018. 4.1.20 ================ BUG FIXES: - Fix memory leak in zone file read of unknown rr formatted RRs. - Fix memory leak when rehashing nsec3 after axfr or zonefile read, in the selectively allocated precompiled nsec3 hashes. 4.1.19 ================ BUG FIXES: - ignore fallthrough compiler warning in flex EOF rule. - Fix warnings emitted by clang for --enable-packed. Alignment is not a problem for x86_64, don't enable packed when the platform requires aligned access. - Fix spelling error in xfr-inspect. - Fix 3392: Fix regression in 4.1.18 for notify lists with ip4 and ip6 targets. - Add test for support of -Wno-address-of-packed-member for --enable-packed. 4.1.18 ================ FEATURES: - xfr-inspect, it is not installed, it prints xfr files from /tmp made with 'make xfr-inspect' in the source dir. - retry timeout between sending notifies dropped from 15 to 3 sec. - NSD sends 16 notifies simultaneously. - configure --enable-packed reduces memory usage, at expense of unaligned reads. Saves about 17%. - Save memory by selectively allocate precompiled nsec3 hashes, saves about 16% memory. - make ip-transparent option work on OpenBSD. - Save about 2% memory by changing usage count size in name tree. - Fix #2871: Increase number of sockets for xfrd transfers. BUG FIXES: - Fix gcc 7.1.1 warnings. - Fix writev compile warning on FreeBSD. - Fix #1446: A corrupted zone file "propagates" to good ones. - nsd-control zonestatus prints wait time between attempts, for zones that are in that waiting time. - Fix collision printout of nsec3 to print name, hash and reverse. - Fix #1567: Change crit to err log level for gettimeofday failure. Add defines for compile without syslog. - Fix crash for DS query when parent and child zones both configured in nsd.conf and parent zone has not loaded properly. 4.1.17 ================ FEATURES: - zone parser parses type AVC (it has TXT format). - Fix #1272: use writev to put tcp length field with data for outgoing zone transfer requests. BUG FIXES: - Fix potential null pointer in nsec3 adjustment tree. - Fix text format of deletes for CDS and CDNSKEY, single 0 to represent empty base64 or hex string. 4.1.16 ================ FEATURES: - zone parser can parse acronyms for algorithms ED25519 and ED448. - Fix 1243: Option to make NSD emit really minimal responses, minimal-responses: yes in nsd.conf. BUG FIXES: - Calculate new udb index after growing the array, fix from Chaofeng Liu. - Fix missing _t to _type conversion for disable-radix-tree option. - Printout serial error with hint it may be too big. - Fix 1228: OpenSSL include is not guarded with HAVE_SSL - Patch for expire state in multi-master when masters includes broken master, from Manabu Sonoda. - minor manpage fix. 4.1.15 ================ BUG FIXES: - Fix nsd-control and ipv6 only. - Squelch zone transfer error address family not supported by protocol at low verbosity levels. - Fix #1195: Fix so that NSD fails on non-compliant values for Serial. - Fix to rename _t typedefs because POSIX reserves them. - Fix that nsec3 hash collisions only reported on verbosity level 3. 4.1.14 ================ FEATURES: - Fix #1132 for SERVFAIL zones perform backoff, and remembers the timeout on next startup. BUG FIXES: - Fix null memcpy for radixtree with single link element. - Robust fix against missing master in tcp_open for xfrd. - Fix wildcards in include: config statements with chroot enabled. - suppress compile warning in lex files. - Fix to try every master once, then wait for timeout or notify. - Save backoff timeout into xfrd.state file, this file has a higher version number now. Old files are skipped silently (causes refresh) and created as new files upon exit. - Fix restart of zone transfers when new config becomes available. 4.1.13 ================ FEATURES: - multi-master-check: yes can be used to check all masters for the last version, using the higher version from the configured masters, from Manabu Sonoda. - Support RR type OPENPGPKEY from RFC 7929. - Can config key algorithms with the digest name, eg. 'sha256'. - configure --disable-radix-tree for about 15% lower memory usage. - for type SRV add A/AAAA to the additional section (if possible), just like we already do for type MX. - more extensible edns option handling. BUG FIXES: - Fix compile warnings about unused result from write and strtol. and signcompare in minmax retrytime. - Fix #812: fix that make depend fails after distribution. - Fix #817: xfrd update failed loop. - Add robustness against unallocated data in nsec3 trees. - Fix README spelling error of BSD license (reported by Joerg Jung). - Fix multimaster for not tried full zone transfer for a expired zone. - Fix #827: fix compile with openssl 1.1.0 with api=1.1.0. 4.1.12 ================ BUG FIXES: - Fix malformed edns query assertion failure, reported by Michal Kepien (NASK). 4.1.11 ================ FEATURES: - When tcp is more than half full, use short timeout for tcp session. - Patch for {max,min}-{refresh,retry}-time from YAMAGUCHI Takanori. - Fix #790: size-limit-xfr can stop NSD from downloading infinite zone transfer data size, from Toshifumi Sakaguchi. Fixes CVE-2016-6173 JVN#63359718 JPCERT#91251865. BUG FIXES: - Fix build without IPv6, patch from Zdenek Kaspar. - Fix #783: Trying to run a root server without having configured it silently gives wrong answers. - Fix #782: Serve DS record but parent zone has no NS record. - Fix nsec3 missing for nsec3 signed parent and child for DS at zonecut. 4.1.10 ================ FEATURES: - ip-freebind: yesno option in nsd.conf sets IP_FREEBIND socket option for Linux, binds to interfaces and addresses that are down. - NSD includes AAAA before A for queries over IPV6 (in delegations). And TC is set if no glue can be provided with a delegation because of packet size. - print notice that nsd is starting before taking off. BUG FIXES: - Fix for openssl 1.1.0, HMAC_CTX size not exported from openssl. - Fix #751: NSD fails to occlude names below a DNAME. - If set without nsd.db print "" as the default in the man pages. - Fix #755: NSD spins after a zone update and a lot of TCP queries. - Fix for NSEC3 with zone signed without exact match for empty nonterminals, the answer for that domain gets closest encloser. - #772 Document that recvmmsg has IPv6 problems on some linux kernels. 4.1.9 ================ BUG FIXES: - Change the nsd.db file version because of nanosecond precision fix. 4.1.8 ================ FEATURES: - #732: tcp-mss, outgoing-tcp-mss options for nsd.conf, patch from Daisuke Higashi. - #739: zonefile changes when mtime is small are detected on reload, if filesystem supports precision mtime values. - RR type CSYNC (RFC7477) syntax is supported. BUG FIXES: - take advantage of arc4random_uniform if available, patch from Loganaden Velvindron. - Fix flto check for OSX clang. - Define _DEFAULT_SOURCE with _BSD_SOURCE for glibc 2.20 on Linux. - Fix #736: segfault during zone transfer. - Fix #744: Fix that NSD replies for configured but unloaded zone with SERVFAIL, not REFUSED. 4.1.7 ================ FEATURES: - support configure --with-dbfile="" for nodb mode by default, where there is no binary database, but nsd reads and writes zonefiles. - reuseport: no is the default, because the feature is not troublefree. - configure --enable-ratelimit-default-is-off with --enable-ratelimit to set the default ratelimit to disabled but available in nsd.conf. - version: "string" option to set chaos version query reply string. BUG FIXES: - Fix zones updates from nsd parent event loop when there are a lot of interfaces. - portability fixes. - patch from Doug Hogan for SSL_OP_NO_SSLvx options, for the new defaults in the ssl libraries. - updated contrib/nsd.spec, from Bálint Szigeti, with new configure options. - Allocate less memory for TSIG digest. - Fix #721: Fix wrong error code (FORMERR) returned for unknown opcode. NOTIMP expected. - Fix zonec ttl mismatch printout to include more information. - Fix TCP responses when REUSEPORT is in use by turning it off. - Document default in manpage for rrl-slip, ip4 and 6 prefixlength. - Explain rrl-slip better in documentation. - Document that ratelimit qps and slip are updated in reconfig. - Fix up defaults in manpage. 4.1.6 ================ BUG FIXES: - Fix #701: Fix that AD=1 set in a BADVERS response. - Fix typo in zonec.c inside error message. - Fix #711: Document that debug-mode yes is used for staying attached to the supervisor console. - Document verbosity 3 prints more information. - nsd-checkconf warns for master zones with no zonefile statement. - Fix start failure when many file descriptors are in use. - The servfail rcode is not printed with a space in the middle. - print failed token for config syntax error or parse error. 4.1.5 ================ BUG FIXES: - Fix #706: default port 53 not opened on ip4 because of getaddrinfo hints initialisation failure. 4.1.4 ================ FEATURES: - RFC7553 RR Type URI support. - removed hardcoded interface limit, --with-max-ips removed. - SO_REUSEPORT support, by default on Linux, or with reuseport: yes. - Admitted axfrs are logged at verbosity 1. Refused at verbosity 2. - --enable-pie and --enable-relro-now options for a safer executable. BUG FIXES: - Fix NSID response for short edns sizes. - Fix that for expired zones NSD performs an AXFR and accepts newer and older serial numbers. - Document that minimal responses only minimizes responses to fit in one datagram. It does not minimize smaller responses. - Fix #618: documented need to list ip-addresses separately in nsd.conf if there are multiple, because the source address of replies can otherwise go wrong. - Fix that notify from nsd-control contains soa serial. - Fix #698 formatting errors and typos in nsd.8.in. 4.1.3 ================ FEATURES: - nsd-control addzones and delzones read list of zones from stdin. - hmac sha224, sha384 and sha512 support, patch from David Gwynne. - max-interfaces raised to 32. BUG FIXES: - Fix #665: when removing subdomain, nsd does not reparse parent zone. - Fix task and zonestat files to be stored in a subdirectory in tmp to stop privilege elevation. - Fix crash in zone parser for relative dname after error in origin. - Fix that formerrors are ratelimited. 4.1.2 ================ FEATURES: - Incoming notifies have serial number logged (at verbosity 1). BUG FIXES: - Remove some duplicate header includes (from Brad Smith). - Fix tcp waiting list for zone transfers where the bind and connect calls fail. - Fix segfault in zone reader on invalid input. (thanks John Van de Meulebrouck Brendgard) - Fix segfault on double origin in zone reader (thanks John Van de Meulebrouck Brendgard). - Fix b64pton out of bounds error on invalid zonefile input. (thanks John Van de Meulebrouck Brendgard) - Fix origin directive from unused old value and subdomain parser failure, reported by John Van de Meulebrouck Brendgard. - Fix use after free after zonefile syntax error followed by ttl or origin directive, reported by John Van de Meulebrouck Brendgard. - Fix syntax error followed by too many TXT elements parse crash reported by John Van de Meulebrouck Brendgard. - Fix buffer overflow in config parse of domain name, reported by John Van de Meulebrouck Brendgard. - Use reallocarray for integer overflow protection, patch submitted by Loganaden Velvindron. - Fix allocation integer overflow checks. - Fix #654: Fix contradiction in notify logging verbosity level. - Fix #655: Fix contradiction in verbosity for zone transfers. - Made log message more consistent, changed 'axfr refused' log message to be more consistent with other messages. Also notify refused. - verbosity 2 logs axfr refused and notify refused. verbosity 1 contains less log messages. 4.1.1 ================ FEATURES: - RFC 7344: CDS and CDNSKEY (read record types). - per zone statistics with --enable-zone-stats, config zone with zonestats: "name", zones configured with the same string are added. - Disabled use of SSLv3 in nsd-control. - nsd-checkconf -f prints out full name of pidfile (with dir). - Synthesize CNAMEs with same TTL as DNAME. BUG FIXES: - Fix that expired zones stay expired after a server restart. - Fix "xfrd_handle_ipc: bad mode" log errors when compiled with --disable-bind8-stats. - Fix #616: retry xfer for zones with no content after command. - Fix char used as array index warnings on NetBSD. - Fix that queries for noname CH TXT are REFUSED instead of nodata. - Fixes for wildcard addition and deletion, speedup for some cases. - Fix that failure to add tcp to tcp base does not leak the socket. - Patch nsd_munin_ from Philip Paeps to use type ABSOLUTE. - Fix spinning NSD with lots of failing transfers, due to pointer comparison using void pointer subtraction (from Otto Moerbeek). - Fix bug#637: fix that nsd.db grows limitlessly, an off by one on one megabyte free chunks, created during AXFRs of large zones, that caused the one megabyte chunk to be leaked. - Fix casts for ctype functions (from Todd Miller). - correct some hyphen-used-as-minus-sign (from Andreas Schulze) in man pages. - Fix zonesdir chroot error message. 4.1.0 ================ FEATURES: - database: "" starts without mmap of database. Less memory is used, zones are read from text zonefile. - optimised zonefile parse code and zonefile write code. - zonefiles-write option in nsd.conf, enabled when database is "". The server writes changed zonefiles to disk every hour. - xfrdfile: "" disables xfrd.state. If enabled, zones that are same as before are not checked for a serial update at server start. - include: "foo/nsd.d/*.conf" works, wildcard glob on includes. - nsd shuts down during init process if given signal. - log-time-ascii option, default yes, with readable timestamp in log. - nsd-control addzone reports if zone already exists. - Fix #564: add nsd-checkzone tool to check zonefile correctness. - Increased default --with-max-ips from 8 to 16, this increases the number of interfaces you can specify in nsd.conf to listen to. BUG FIXES: - Fixed shutdown message sporadically not printed on exit (Thanks Anand Buddhdev). - Documented zonefile %s syntax in nsd.conf man page. - Fix manpage to put colon after zonefiles check and write. - Change from 'Zone" to "zone" with ".. serial .. is updated" log message. - Changed maxbackoff for no-content secondary zones from 4h to 24h. - Fix print filename of encompassing config file on read failure. - Fix delete or rename of a lot of zones and make it take a non-enormous time. - Speed up deletion of zone contents a lot, (56s to 1s), speeds up delete, rename and AXFR for zones. - Fix #571: unused variable and incompatible pointer warnings when compiled on a system without INET6. - Fix write_socket return value check in server.c (Thanks Brad Smith, Mark Kettenis). - Fix that xfrd reaps children also if the signal is lost. - Fix #577: makefile incorrectly installed manpages from srcdir. - Fix #587: Default value for statistics is 0. - Fix #553: Improve TXT parsing. - Fix #590: rrl log does not print wildcard as a star but escaped. - Fix #591: rrl log messages at verbosity level 1. - fix strptime implicit declaration error on OpenBSD. - Fix -O3 compile flag to -O2 to avoid miscompilations. - Allow user to override the -g -O2 CFLAGS in ./configure. - Fix endian.h include for OpenBSD. - Fix #600: document that provide-xfr provides AXFR and not IXFR. - Fix rising-load-average or memory-leaks in OSes (Linux since 2.6), that keep track of all past process parents, or leak memory for them. Fix makes it so there is no very deep string of process parents. - Remove .LP after .SH in man pages. 4.0.3 ================ BUG FIXES: - Fix nsd.db unclean close check. Previous databases are considered unclean by the code and are created anew. - Adds nsd.db larger than 400Tb check for sanity. Also test if filesize as documented in the file is correct. - nsd waits for tasks to complete on stop, prevents nsd.db corruption. - fix to not delete tmpdir too early in shutdown process. - disabled udb checking functionality that made it very slow, this was enabled when enable-checking was turned on. 4.0.2 ================ FEATURES: - Return REFUSED for queries to non-hosted zones. BUG FIXES: - Fix expired zones to give SERVFAIL, also when parent zone loaded. - documented nsd-control zonestatus output in nsd-control manpage. - remove mention of nsdc from nsd-checkconf manpage. - Disabled recvmmsg and sendmmsg usage by default because kernel versions have implementation issues: ipv6 ignored, security issues. - Detect libevent2 install automatically by configure, and use event2 header files if necessary. - Fix #551: change Regent to Copyright holder in the LICENSE, to match the definition on opensource.org for the BSD License. - Fix #552: zonefile loads on nsd-control reconfig when the name of the file has changed. - Fix leak of zone name after zonefile read and fix malloc too large that would be leaked in the radix tree. - Fix from 3.2: make SOA RDATA comparisons in XFR more lenient (only check serial). - Fix that NSD will delete and recreate not-clean-closed databases. 4.0.1 ================ FEATURES: - recognizes ip-address and interface as synonyms for convenience. - Support for EUI48 and EUI64 RR types enabled by default (RFC 7043). - Support for CAA RRtype (RFC 6844). - NSID can be set with "ascii_somestring" in ascii. BUG FIXES: - Fix xfrd when zone transfer TCP contains zero length packets. - Fix for NSEC3 zones where parent zone is co-hosted, also NSEC3, because AXFRs overwrote nsec3 administration in the child zone. - Fix that bad IXFR updates do not result in double SOA records, and that an AXFR is started (attempted) when the zone state seems to be inconsistent with the master's zone state. - Log ip address for sendto and sendmmsg failures. - Fix segfaults after read of zones with rr type WKS from zonefile. - Seed PRNG for openssl at start of daemon, fixes SSL connection issue. - Bugfix #534: IXFR query loop over UDP for zones that are unchanged. - (same as in 3.2.16): fix wildcard cname to nxdomain repeated rrset. - (same as in 3.2.16): Bugfix #542: Match RRSIG TTL with SOA TTL in negative response. - Check if configure in srcdir collides with outofdir build. - Fix #546: output format errors in nsd_munin_ (Thanks Tom Hendrikx). - Fix printout of high-chars in TXT on NetBSD. 4.0.0 NSD 4.0 =============== FEATURES: - documented in doc/NSD-4-features. Change configuration without restart, direct nameserver control with nsd-control, support a higher number of zones. Higher performance (compared to NSD3). - nsdc is gone. Use kill -HUP for reload (also checks if zonefiles have changed and rereads them), and kill -TERM for quit. Or use nsd-control for detailed control. - cron job for nsdcpatch is gone. nsd-control write creates zonefiles. - nsd.db has a new format that compacts itself when it is changed, thus nsdc patch is no longer necessary. - nsd.db is memory mapped, NSD needs (part of) that mmap in ram. - tcp-count can go above 1000; epoll/kqueue support with libevent. - nsd-control reconfig for updates with no restart (zones, keys, ..) - nsd-control-setup to create keys for nsd-control (enable nsd-control with remote-control: yes in nsd.conf). - the NSD 3 feature of special zone stats are not ported to 4 yet, as it would entail a complete reimplementation of the feature. FEATURES (incremental from BETA5): - configure --disable-recvmmsg for compat with older Linux kernels, by default it autodetects support in the kernel on the buildmachine. - Fix time at 2038, uint32s changed to time_t, support 64bit time_t. - Fix use of 32bit time, for 2038, thanks to Theo de Raadt for patch. BUG FIXES (incremental from BETA5): - Bugfix #518 Incorrect RRL prefix length option names in nsd.conf man page from Ville Mattila. - Fix that xfrd, and nsd-control, does not stop responding when reload errors out. The pid is sent like it should by server_main. - Fix that EOF in quoted string error does not cause reload to exit. - Fixup errors from the stack code checker. - Removed use of random when arc4random is available. Thus, random and srandom are then not linked with the executable. - Fix segfault with no logfile and chroot (Thanks Patrik Lundin). 4.0.0b5 BETA 5 release of NSD 4.0 ================================== FEATURES: - Optimizations for startup, qps and tcp speed, beta bug fixes and merge with code changes with NSD 3.2.16. - nsd-mem tool (make nsd-mem) to estimate memory usage. - Same as NSD 3.2.16: --enable-draft-rrtypes(EUI48, EUI64), rr-slip, rrl-ipv[46]-prefix-length, ip-transparent config options. - configure option --disable-flto. - improved RRL logging (query details that caused blockage). - nsd-control status prints out ratelimit if ratelimit is enabled. - nsd-control verbosity prints out verbosity level without argument. - Fix #491: pick program name (of executable) as syslog identity. - printout percentage for long activities (to log). After about 5 seconds have passed. BUG FIXES: - The same fixes up to NSD 3.2.16. - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify. - Fix tcp zonetransfer pipeline lookup function. - Fix compile on bigendian netbsd alpha. - Fixup the growth and shrinkage of nsd.db. This should use less calls to remap and change the file and mmap size. - notify information is logged at correct verbosity level, 1. - Fix memory statistics in nsd_munin_. - faster nsec3 updates. - Fixup contrib/bug390.patch for 4.0.0b4. - remove leak of nsec3. - allocate radixtree in region for small (5%) total savings and about 15% savings in the radixtree itself (due to many small alloc savings in region). - Patch from Lukas Wunner that makes nsd.conf include files work inside chroot/etc environments on repattern and reconfig. - Fix race on exit of nsd, for restarts, so that the pidfile-pid process waits until port53 has been closed before exiting. - Patch from Lukas Wunner that makes chroot more consistent. Make all paths absolute with the chrootdir in front, or use an absolute zonesdir with other paths relative to that. - Fix segfault on repeated reconfigs, double free of zone apex name. - Fix zone parser allocations are put in the db region. - Fix memory leak in zone parser for txt record. - Optimizations: -O3 if possible (user can override CFLAGS), udp buffers are set to 1m by default (if socket options exist), use recvmmsg and sendmmsg, or only recvmmsg, or recvfrom. - nsd.db 12% smaller, no nsec3 hash storage. Also ups udb version because of the format change. The nsd.db is recreated when a different version number is detected on startup. - Fix region-allocator for speedup of load and change of large data. - Increase tcpbacklog default to 256 (silently capped to 128 on BSD). For remote control keep it at 16, it has less TCP load. It does not actually increase TCP performance (some except), but reduces connection loss when there is a spike in TCP connections. - unlink xfr file if transfer is stopped, timeouted or interrupted. And unlink xfr file in progress when the zone is deleted. 4.0.0b4 BETA 4 release of NSD 4.0 ================================== BUG FIXES: - remove -fwhole-program gcc flag usage. We cannot reliably detect if it works without failure. - fix zonefiles-check: entry in nsd.conf - fix gcc warning, do not use uninit value for rng init. - remove printout of "bad transfer" to the log for notimpl. - printout log less verbosely, not every axfr packet. - RRL documented in nsd.conf.sample - Fix is_apex flag for zones read from udb. - Fix that nsec3 zones are precompiled when read from udb. This caused assertion failures. - Less printout of 'bad transfer'. - Fix AXFR of NSEC3 slave zone. - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify on verbosity 2. 4.0.0b3 BETA 3 release of NSD 4.0 ================================== BUG FIXES: - applied patch from Robin Hack to remove double pid file truncation. - repattern is called reconfig (because most config options are picked up, except for superuser options (chroot, logfile, port)) - document that the zonefile attribute can be empty. - documented that the _implicit_ pattern names are used internally. - Added zonefiles-check option, default yes, check mtimes of zone files on sighup and startup (from Robin Hack). - Fix spurious assertion failure for some rrl blocks. - Tabs and spaces nicer in nsd.conf.sample. - List libevent in README. - Fix configure for gentoo gcc and headers. - do-ip4 and do-ip6 nsd.conf options just like unbound. - do not leave task files in /tmp if nsd fails to startup because of file permissions. - create xfrdir on make install (does not remove on make uninstall, because this could be /tmp). - Fix segv if xfrdir does not exit. - log ip address with tcp failure. - Fix time calculation of zone transfer. 4.0.0b2 BETA 2 release of NSD 4.0 ================================== FEATURES: - Add and remove zones from nsd.conf with nsd-control repattern. - Merge changes from 3.2.15 (such as xname-rcode fix). BUG FIXES: - Fix for use with libev. - 'nsd-control start' runs an absolute path to start sbin/nsd. - Fix for use with libevent-2.1.2. - --with-logfile sets the logfile inside the example documentation. - Fixed addzone and delzone inside chroot (thanks Will Pressly). - Fix make outside of source directory. 4.0.0b1 BETA 1 release of NSD 4.0 ================================== FEATURES: - add and remove zones without restart. - nsdc is gone, use nsd-control for direct server control. - performance increases - support lots of zones - and more ... - longer desc in doc/NSD-4-features BUG FIXES: - core code is fixed like 3.2.15r3763 (12 dec 2012). 3.2.16 (development branch) ================================= FEATURES: - New config option "ip-transparent:" to allow NSD to bind to non local addresses. Default no. - Use IPV6 minimum MTU settings with TCP to reduce failures that are caused by delays in learning working PMTU when communicating through a tunnel. - Bugfix #496: Support for EUI48 and EUI64 RR types. Experimental, turned off by default. Enable with --enable-draft-rrtypes. - New config option "rrl-slip:" to set the average number of packets discarded before we send back a truncated response. - New config option "rrl-ipv4-prefix-length:" and "rrl-ipv6-prefix-length:" to set the prefix lengths. - Improved RRL logging, also print triggering query src address and QTYPE. - Provide RRL documentation in nsd.conf.sample. BUG FIXES: - Bugfix #357: Parent process waits until children closed down sockets, to prevent NSD failing to bind to sockets when restarting. - Bugfix #487: lookup3.c determine endianness for BSD systems. - Bugfix #491: pick program name (0th argument) as syslog identity. - Bugfix #494: Exit with return code 1 if socket code fails. - RRtypes ASFDB, RP, RT should not compress dnames. - Fix outgoing-interface: Don't fail if family is IPv6 but only IPv4 outgoing-interface is set, or vice versa. - RRtypes ASFDB, RP, RT should not compress dnames. - Check that zone directory is within chroot directory. - Better XFR checking, fallback to AXFR (if allowed) if three malformed XFR packets have been seen. 3.2.15 ================================= FEATURES: - Support for ILNP RR types: NID, L32, L64, LP (RFC6742). - RRL, --enable-ratelimit at configure time and config options. - TSIG initialization only fails when there is no digest found at all. BUG FIXES: - Bugfix #478: Declaration after statement (for gcc 2.95). - Bugfix #483: Better error message in case of TSIG error. - Bugfix #485: TTL should not be greater than 2^31 - 1. - Fix RCODE when CNAME loop final answer does not exist, should return NXDOMAIN as stated by RFC 6604. - Fix --disable-full-prehash bug, where after multiple incoming IXFRs, NSEC3 can be removed unjustified. 3.2.14 ================ FEATURES: - TCP writev support. BUG FIXES: - Fix build on OpenBSD (thanks Oliver Peter). - Prioritize notify sender for requesting XFR (thanks Ilya Bakulin). - Fix crash in zonec if TXT string too long (thanks Ilya Bakulin). - tzset before chroot for correct timezone (thanks Camiel Dobbelaar). - Fix --disable-full-prehash bug when nsdc patch happens while ixfr too, it did not rehash the new database. - Bugfix #464: Conditionally define MAXHOSTNAMELEN. 3.2.13 ================ BUG FIXES: - Fix for nsd-patch segfault if zone has been removed from nsd.conf (thanks Ilya Bakulin). - Bugfix #460: man page correction - identity. - Bugfix #461: NSD child segfaults when asked for out-of-zone data with --enable-zone-stats. [VU#517036 CVE-2012-2979] 3.2.12 ================ BUG FIXES: - Fix for VU#624931 CVE-2012-2978: NSD denial of service vulnerability from non-standard DNS packet from any host on the internet. http://www.nlnetlabs.nl/downloads/CVE-2012-2978.txt 3.2.11 ================ FEATURES: - Fallback to AXFR if IXFR is unknown at the primary. NSD considers IXFR unknown at the primary if there is a negative response for the IXFR RRtype. This does not override the value for 'allow-axfr-fallback'. - Allow for reading in new DNSKEY algorithm mnemonics (RFC5155, RFC5702, RFC5933, and RFC6605 (ECDSA)). - Zone statistics, enable with --enable-zone-stats. This stores the BIND8 stats per zone in a configurable statistics file. This option does not scale and should therefore not be enabled when serving many zones. - Support for TLSA RRtype (DANE). BUG FIXES: - Fix for qtype ANY for a wildcard domain in NSEC signed zone: Don't add the wildcard domain NSEC into the answer section. Instead, put the wildcard expanded NSEC into the answer section and keep the wildcard domain NSEC in the authority section. - Fix for accept spinning reported by OpenBSD. - Fix restart failed due to bad ixfr packet because of zone removed from nsd.conf. - Bugfix #453: typo in nsdc man page. OPERATIONAL NOTES: - NSD uses the query name for dname compression again (Fix #235 had as side effect that this didn't happen anymore and is hereby undone). 3.2.10 ================ BUG FIXES: - Bugfix #421: Truncate pidfile on shutdown, before unlink. - Bugfix #423: Fix slow zone transfer processing due to 'Fix is_existing flag for ENT' bugfix. - Fix bug #430: segfault when MAX_INTERFACES set to more than 65K. - Fix configure.ac strptime check for gcc 4.6.2, acx_nlnetlabs update. 3.2.9 ================ FEATURES: - Minimize responses to reduce truncation: NSD will only add optional records to the authority and additional sections when the response size does not exceed the minimal response size. The minimal response size is 512 (no-EDNS), 1480 (EDNS/IPv4), 1220 (EDNS/IPv6), or the advertized EDNS buffer size if that is smaller than the EDNS default. The feature is enabled by default. You can disable it by configuring NSD with --disable-minimal-responses. - Less NSEC3 prehashing. This will make NSD handle zone transfers faster, but will decrease the performance of NXDOMAIN and wildcard NODATA responses. Full prehashing is enabled by default. If you want less NSEC3 prehashing, configure NSD with --disable-full-prehash. Thanks Secure64 for the patch. BUG FIXES: - Bugfix #302: nsd accepts XFR but refuses to re-read the slave zone. - Bugfix #365: set patch style and zonec verbose for nsdc. - First step of bug #369: RRSIG DNSKEY sets zone to be treated DNSSEC. - Bugfix #375: typos in nsd.conf.5. - Bugfix #381: Binary escaped and transfers. - Bugfix #397: Don't allow relative domain names as origin in $INCLUDE directives. - Fix printout of IPSECKEY by nsd-patch. - Fix is_existing flag for ENT when domain that has a shared ENT is deleted by IXFR. (ENT == Empty Non-Terminal) - Fix bug if the zonefile is changed for a secondary but stored transfers are applied, and stop it from applying ixfr to empty zone. The zone is flagged with error and AXFR-ed. - Fix to have no authority NS set processing for CNAMEs. - Fix nsd-checkconf to check tsig algorithms properly. - Set the AA bit on responses that have an authoritative CNAME. - Fix denial of existence response for empty non-terminal that looks like a NSEC3-only domain (but has data below it). OPERATIONAL NOTES: - nsd.db version number increased because NSD 3.2.7 and earlier zonec is not compatible due to the TXT strings change. Please run nsdc rebuild before running NSD 3.2.9 and later versions. 3.2.8 ============= BUG FIXES: - Do setusercontext() before chroot(), otherwise login.conf etc. are required inside chroot. - Bugfix #216: Fix leak of compressiontable when the domain table increases in size. - Bugfix #348: Don't include header/library path if OpenSSL is in /usr - Bugfix #350: Refused notifies should log client ip. - Bugfix #352: Fix hard coded paths in man pages. - Bugfix #354: The realclean target deletes a bit too much. - Bugfix #357, make xfrd quit with many zones. - Bugfix #362: outgoing-interface and v4 vs. v6 leads to spurious warning messages. - Bugfix #363: nsd-checkconf -v does not print outgoing-interface ok. - Bugfix: nsd-checkconf -o outgoing-interface omits NOKEY. OPERATIONAL NOTES: - Use 'make clean' to clean up files that make created. - Use 'make realclean' to also clean up files that were generated by running ./configure. - Use 'make devclean' to also clean up autoconf, autoheader files. 3.2.7 ============= BUG FIXES: - Bugfix #253: Don't put NS RRs in a response with QTYPE=DS. - Bugfix #320: use arcrandom(4) for QID generation if available. - Bugfix #328: nsd-checkconf overrun. - Bugfix #343: nsdc update fix. - Bugfix #347: Wrong NSEC3 returned for nodata response QTYPE=DS no delegation. - Bugfix: Allow for huge amount of strings in TXT (and other) records. - Bugfix: nsdc can now deal with tsig algorithms other than hmac-md5. - Fixed several parts in the documentation, including #306, #345. 3.2.6 ============= BUG FIXES: - Bugfix #314: correctly print NSEC next field, escape spaces and fix label overflows. FEATURES: - Expand command line option '-a' and config option 'ip-address:' with port number. OPERATIONAL NOTES: - Configure options --disable-dnssec, --disable-nsid, --disable-tsig are removed. - Configure option --max-interfaces is renamed to --max-ips. 3.2.5 ============= BUG FIXES: - NSD will not start if chroot is configured, but changing root is not possible (it used to ignore the badly configured chroot). - Make use of the more secure strl* functions. - Bugfix #303: spelling error. FEATURES: - New option 'nsid:', to specify the NSID (Bugfix #298). - The default chroot can be set with --with-chroot=. If not set, by default chroot will not be used (thanks Jakob Schlyter). - Optimized zonec and b64_pton compatibility code (thanks Martin Svec). - Optimized memory allocations. Use mmap/munmap instead of malloc/free. Experimental, by default off. Enable it at build time with --enable-mmap (thanks Martin Svec). OPERATIONAL NOTES: - NSID support is now enabled by default. 3.2.4 ============= BUG FIXES: - Bugfix #269: Additional C99 syntax. - Bugfix #276: Zonec prints debug data to stderr. - Bugfix #286: Document verbosity levels in nsd.conf manual page. - Bugfix #288: Ignore SIGHUP to child processes. - Fix typo in include file for setusercontext. FEATURES: - Support DLV records. - New option 'tcp-query-count:', to limit the maximum number of DNS queries on a single tcp connection. - New option 'tcp-timeout:', to override the default tcp timeout. The default can also be set at build time, --with-tcp-timeout=. - New option 'notify-retry:', to configure how many times NSD should retry a NOTIFY message. - New options 'ipv4-edns-size:' and 'ipv6-edns-size:'. to set your preferred EDNS buffer size. OPERATIONAL NOTES: - UDP/IPv4 sockets have new options set that will disable the DF flag in IP packets. 3.2.3 ============= BUG FIXES: - Bugfix #236: Allow RRs before the SOA in a zonefile. - Bugfix #249: Remove the C99 code. - Bugfix #253: Don't put NS RRs in a response with QTYPE=DNSKEY. - Bugfix #263: Make TSIG algorithm comparison case insensitive. - Bugfix #266: Build failed on systems without strptime. - Bugfix: install hickup. - Fix to use 4096 EDNS limit for IPv6 on Linux. 3.2.2 ============= BUG FIXES: - Off-by-one buffer overflow fix while processing the QUESTION section. - Return BADVERS when NSD does not implement the VERSION level of the request, instead of 0x1. - Bugfix #234. - Bugfix #235. - Reset 'error occurred' after notifying an error occurred at the $TTL or $ORIGIN directive (Otherwise, the whole zone is skipped because the error is reset after reading the SOA). - Minor bugfixes. 3.2.1 ============= OPERATIONAL NOTES: - NSD will now fallback to AXFR, only if the master does not support IXFR. - You can adjust nsdc patch to skip textfile patching. This will increase the patching process, but will not output to zonefiles anymore. By default, this is off. BUG FIXES: - When configuring, don't do strptime test when cross-compiling. - Bug #230: Output non-error messages to stdout. - Better error message when ixfr.db old file format is read. - Bug #218: shared UDP query for all interfaces. - Bug #222: Remove bashism from nsdc script. - Nicer check for SHA-256 functionality. - Fixed some minor memory leaks that occurred on reload. - nsdc: check if a lockfile has not gone stale, when lock failed. - Bugfix strptime compatibility function FEATURES: - New configuration option 'allow-afxr-fallback', "yes" by default. If set to "no", NSD will never do AXFR fallback, even if the master does not support IXFR. - Allow file rotation on nsd.log. - The new nsd-patch options -s and -o allows you to skip writing zonefiles and store the output directly to a database file, respectively. 3.2.0 ============= OPERATIONAL NOTES: - Format of ixfr.db has changed. When you are planning an upgrade to the new NSD release, make sure to process the old ixfr.db before starting the new release (by running nsdc patch). - IXFR is transmitted over TCP by default instead of UDP. If you want to continue the use of IXFR/UDP, please modify your zone configuration file to: request-xfr: UDP 1.2.3.4 tsigkey We strongly recommend to enable TSIG if you send IXFR over UDP. When all masters fail to transmit IXFR/UDP, slave will fallback to IXFR/TCP and eventually AXFR/TCP. - nsd-patch prints errors to stderr instead of stdout. BUG FIXES: - Only normalize dnames in rdatas when rrtype is listed in RFC 4034, section 6.2: Canonical RR Form, following draft-ietf-dnsext-dnssec-bis-updates (affects RRSIG and NSEC records). - Typo in zonec manpage. - Bugfix in log_finalize. - Fix race condition between nsdc patch and server reload. FEATURES: - AXFR/TCP fallback in case of failing IXFR zone transfers. - RFC 4635: support for hmac-sha1 and hmac-sha256 TSIG algorithm identifiers, "Bugfix #130". - Configure the source ip-address for notifies (master) and zone requests (slave) in nsd.conf, "Bugfix #148". - nsd-notify and nsd-xfer allow you to configure the outgoing hostname and source port, in addition to the source address. - Additional debug and verbose log messages. 3.1.1 ============= BUG FIXES: - Try to avoid race conditions with NSD reloading and nsdc running, by writing pidfile before closing old parent process. - Fixed NSEC3 memory leak in the case NSEC3 is not needed. - Fixed some memory leaks that happened on error, mostly on zone transfer errors. - Bugfix #191: nsd-checkconf allowed only (max_interfaces-1) interfaces. FEATURES: - The number of maximum interfaces allowed is configurable with --with-max_interfaces= (thanks John Lightsey). 3.1.0 ============= OPERATIONAL NOTES: - Default locations of nsd.db, ixfr.db & xfrd.state are changed to the /var/db/nsd directory. BUG FIXES: - Zone compiler gives more sane error messages when out of diskspace and bug #172: when compiling single zone file. - Changed man pages format from mdoc to mansun, to support the Solaris OS. - Log tcp read error only when connection not reset by peer or when verbosity level is high. - RRs are compared without checking the TTL value. FEATURES: - NSD is now NSEC3 enabled by default. You can disable it by configuring NSD with --disable-nsec3. - Added "hide-version" configuration setting. Enabling this feature stops NSD from answering to CHAOS class version requests. - Added bind2nsd 0.5.0 (http://bind2nsd.sourceforge.net) in contrib/. - Report source and zone for denied AXFR attempts. 3.0.8 ============= FEATURES: - Better logging for nsd-notify (show 'broken' zone) - Add configuration for chkconfig to control nsd service. BUG FIXES: - Fixed nsdc start when nsd already running: do not initialize server, since it is already running. - Fixup bug where data related files are looked up in the wrong directory when chrooted with chrootdir ending with a slash. - Fixup bug where nsd would return FORMERR if received an edns query with version set to zero and rdlen larger than zero. - Fixed strptime, so that zonec will also work on systems with broken strptime (like leopard :-)) - Do not answer nsec3 wildcard information when DO bit is not set - Better logging when creating database failed. - Various spelling errors 3.0.7 ============= BUG FIXES: - Error handling for malformed IXFRs improved. - Fixed man pages, consistent syntax. 3.0.6 ============= FEATURES: - Report source and zone for denied AXFR attempts. BUG FIXES: - More elegant handling of malformed nsec3 records from a zone transfer. - Fixup ignored return value in region-allocator. - Added bind2nsd 0.5.0 (http://bind2nsd.sourceforge.net) in contrib/. 3.0.5 ============= BUG FIXES: - Fixed problem with reload waiting very long. If the OS has a raging herd problem, NSD could block in a UDP operation and that process would stop reload from finishing. Made UDP sockets nonblocking. - Made TCP listen sockets nonblocking. NSD could block in accept. - Handle the new CERT RDATA types defined in RFC 4398 (submitted by Mans Nilsson). - Fixed a bug where zonec would choke on unknown CERT RDATA types. - Change nsd-notify retry timer from linear into exponential backoff (submitted by Mans Nilsson). - Debug flag (-d) behavior changed. Nsd now also forks children when run in debug mode. - Added verbosity mode (-V ) for extra operational logging. - zonesdir default is /etc/nsd. This can be overridden in nsd.conf. - if clients drop the tcp connection this does not result in a logfile entry, unless verbosity is set 2 or more. 3.0.4 ============= BUG FIXES: - zonec will print an error when other data is put next to a CNAME. - Fixup unaligned memory access that could occur when reading ixfr.db with a partial transfer inside. - Fixup for the WKS RR type printout by nsd-patch and nsd-xfer. - Error message 'could not read database CRC' now only given on error. - ./configure --zonesdir= now works to set a default value for the zonesdir: nsd.conf directive. Set zonesdir: "" to disable the change of directory. - Bug: reload crashes with log message 'continuing with old database', and after that no more zone updates. Manual fix is to kill -HUP, but now fixed in software to try to reload again (and again). - Small speedup where xfrd could briefly be busy-waiting. - If master sends IXFR with glue that is already present in the zone this is silently accepted. Printed in debug mode -L 2. To make the log file smaller. - Exponential backoff for zones that never worked to max of 4 hours. For expired zones the SOA retry values are used. - allow-notify acl entries 'NOKEY' match only queries without TSIG. - Answers to valid notifies contained wrong RR counts in the header. The notifies were processed correctly, but now the acknowledgement reply is in correct DNS format. FEATURES: - Added contrib/nsd.zones2nsd.conf python script to convert NSD 2 to NSD 3 config files, contributed by Stephane Bortzmeyer. - The nsdc control script will print 'nsd startup failed' if the nsd executable does not start (due to bad permissions, bad config, ...). 3.0.3 ============= BUG FIXES: - Bug #152: NSD would not use the identity from nsd.conf, fixed. - Bug #153: When running with thousands of secondary zones, NSD would run out of UDP sockets. Caused crash on FreeBSD, errors on Linux ('out of file descriptors'), depending on ulimits. Fixed. - Fixed getaddrinfo error message to be more descriptive. - Fallback to ip4 if getaddrinfo fails for ip6. - Will no longer lose a notify message during reloads (IPC). - Will no longer lose transfer in progress when notified for that zone. - Nicer error when operator forgets to rebuild after deleting a zone. 3.0.2 ============= BUG FIXES: - Nice error from zonec on a wrong configuration zone name. - Nicer warning from zonec when starting secondary zone with no zone file for the first time. - nsdc makes more portable use of 'which' (for SunOS5.9/bash2.05). - Bug #143: Improved handling of zonesdir: directive and relative pidfile, database, diff file, xfrdfile paths in nsdc.sh and nsd-patch. They would not find the files. - Bug #144: LOC RRtype default values for precision wrong. Fixed. - Bug #145: NSD failed to reload cases of simultaneous zone transfer. - Bug #146: NSD fails to write to xfrdfile when chrooted. Fixed. Also fix for difffile when chrooted. - Bug #147: NSD runs out of memory. Fixed, memory is reused. Occurred when running NSD with very big zones and large updates. - nsd -L 1 logging is smaller, -L 2 contains all debug information. (only available for debug compiles). - Bug #149: Fixed text for NOTAUTH error code. When notify is not authorised REFUSED error code returned instead. 3.0.1 ============= BUG FIXES: - nsd-patch prints SOA record at start of zone files. 3.0.0 ============= FEATURES: - AXFR/IXFR zone transfer supported. - NSD requests but does not provide IXFR transfers. - NSD keeps track of SOA timeouts for secondary zones. - TSIG authentication supported. - For queries, for notifies, for zone transfers. - NOTIFY messages of zone updates, incoming and outgoing. - DNAME type is supported, including CNAME synthesis. - config file, nsd.conf(5), place to put TSIG keys, server settings, and lists of ip-addresses/ranges for AXFR/IXFR and NOTIFY. - prepared for NSEC3 (--enable-nsec3), experimental code for testing in workshops. - prepared for NSID (--enable-nsid), experimental code for testing in workshops. OPERATIONAL NOTES: - config file needed, nsd.conf(5) supersedes nsd.zones and nsdc.conf. - AXFR transfers are denied by default. Allow in config file. - Zones only become secondary with "request-xfr:" items in config file. - NSD produces "ixfr.db" file with a journal of zone transfers. Use nsdc patch to merge changes back to zone files and remake db. - NSD produces "xfrd.state" file with zone timeout information. The file is text formatted. - NSD sends notifies automatically, nsd-notify is deprecated and will be removed from the package. - NSD requests AXFR/IXFR and reloads the updates automatically, nsd-xfer is deprecated and will be removed from the package. - Check your config file with nsd-checkconf. BUG FIXES: - contains all bug fixes from 2.3.5 and before. - The sighandler() bug is fixed more thoroughly, by using pipes for interprocess communication. - CNAMEs are followed by the server to different zones and information from that zone is returned. This saves a followup query. - bug fixes (ported) 2.3.6. - nsd-notify will retry max 15 times 5 second retries. - Bug #105: nsdc lacks locking, fixed locking for root user. - Bug #134: nsd: make -N work again - Bug #135: Typo in locking code for nsdc, fixed. - uninitialised variable fixed. - unaligned memory access (on Solaris SPARC), in zonec LOC parsing, fixed. - Bug #138: nsd aborts trying to bind all interfaces if ip6 is not enabled, instead it will fallback to ip4. - Bug #139: resync timer for stats to whole minute. - Bug #140: NSD did not clear CD bit on authoritative answers. - Bug #141: NSD did not clear flags on a formerror reply. 2.3.5 ============= BUG FIXES: - Bug #132: regression, nsd: fix compile with --disable-ipv6 - Makefile: remove gnuisms 2.3.4 ============= BUG FIXES: - Unknown type codes for type code numbers > 48 and < 97 work again. (this implies --enable-checking can be enabled again) - nsd: sighandler() fixes - Bug #118: nsd: nsd_notify waits for a response. Will retry the notify after a timeout. - Bug #124: $(DESTDIR) was added to Makefile.in. - Bug #128: zonec: parser can handle \\ at the end of a string. - zonec: lexer: add \r to the newline delimeter - zonec: use strtol with an explicit base 10 as parameter. (Scott Rose, Roy Arends) - nsd-xfer: print human readable error codes. Change logging to be more in line with the rest 2.3.3 ============= BUG FIXES: - Apply the correct patch to nsdc.sh.in. 2.3.2 ============= FEATURES: - Bug #101: add support for the SPF record. BUG FIXES: - Bug #100: replaced non-portable use of timegm(3) with portable implementation (mktime_from_utc). - Bug #103: nsd: trim the SOA's TTL to the MINIMUM value when returning a negative answer. - Bug #104: nsd: add a time_t timestamp to the log when logging to a file. - Bug #105: nsdc: use a lock file when rebuilding the database (patch by Jakob Schlyter/Ted Lindgreen/Sebastian/Ondrej Sury). - Bug #106: zonec: don't walk all 256 NSEC windows when that is not needed. - Bug #107: zonec: fixed a crash when encountering bad unknown rdata. - nsd: Don't print: "error: nsd is already running as , stopping" when in fact NSD continues to run. - nsd: Minimize the race window in sig_handler(). 2.3.1 ============= BUG FIXES: - zonec: Don't crash when generating error messages outside of zone files. - nsd: when logging to a file the pid is now printed. - nsd: Reset 'boot' time in statistics when reloading the database, since the statistics are reset to 0 on a reload. - nsd-xfer.c: Added '-a' option to specify local address to connect from. Original patch supplied by Walter Hop . - Bug #98: Allow mnemonics for DS and RRSIG algorithm field. 2.3.0 ============= FEATURES: - DNSSEC is now enabled by default. NSD should be fully compliant with RFC4033, RFC4034, and RFC4035. BUG FIXES: - nsd: Ensure that the number of -a flags does not exceed the maximum specified by MAX_INTERFACES in config.h. - nsd-xfer: Use serial number arithmetic (RFC1982) for the zone serial check - nsdc: Don't pass (fake) serial number to nsd-xfer if the zone file does not exist. - zonec: Loading many zones would cause namedb_find_zone to slow down, performance patch by Kazunori Fujiwara. - Bug #96: nsd-xfer did not handle 8-bit domain names correctly. 2.2.1 ============= FEATURES: - The message priority is now included when logging to a file. BUG FIXES: - Zero length RDATA using the unknown RR notation was not working (except for the APL RR type). - Bug #93: './configure' error message containing a comma must be properly bracketed. - Bug #94: nsd-xfer: Handle unexpected EOF when receiving AXFR data. Timeout if no data is received for more than 120 seconds (see the TCP_TIMEOUT parameter in config.h). - Bug #95: An owner starting with an asterisk label ("*") was being treated as its own wildcard child. 2.2.0 ============= FEATURES: - nsd-xfer: replacement program for named-xfer to perform zone transfers using AXFR. TSIG is supported by nsd-xfer but not yet by the nsd server. DNSSEC is also supported. TSIG requires OpenSSL version 0.9.7 or higher, configure using --disable-tsig if you do not have OpenSSL installed. Configure using --with-ssl=path if OpenSSL is not installed at a standard location. CODE CHANGES: - New data structure 'buffer_type' for representing binary buffers that can be read, written, and resized. Data in these buffers is stored in network byte order. This data structure replaces the iobuf field of 'struct query'. BUG FIXES: - Fixed endian problem in WKS record. - Protocol can now be specified numerically in WKS record. - Allow escape sequences (\DDD) in TTL, RR class, and RR type. - The zone compiler now accepts many more characters in unquoted strings such as domain name labels. The characters no longer need to be escaped with a backslash. - Close included files after reading. - Maximum TCP message size is now 65535 bytes. AXFR response packets are still limited to 16383 bytes for optimal compression of dnames. - The TSIG key for AXFRs can now also be stored in the file .tsiginfo. This makes it possible to use TSIG with multiple master servers. - Signals are no longer blocked while performing I/O so the server should respond quicker to signals. - Fixed parsing of LOC rdata. Fractions and altitude were not handled correctly. 2.1.5 ============= BUG FIXES: - Bug #90: handle \000 in TXT records correctly - Fixed undefined behavior in the use of vsnprintf when logging messages. This caused crashes on Linux/PPC. 2.1.4 ============= BUG FIXES: - nsdc: Fixed a typo that caused AXFRs to stop working. 2.1.3 ============= FEATURES: - nsd: The pidfile can be specified using the '-P' option. BUG FIXES: - Bug #87: allow @ in the rdata - Bug #88: allow ::FFFF:ipv4addr in AAAA records - Bug #89: Count the number of queries received over TCP, instead of the number of TCP connections. - Zonec: when - is used as input, set the filename to 'STDIN'. - The nsdc script handles failed AXFRs more gracefully. - NSD emits an error when it sees bitlabels (RFC 2673). - Only copy the CD bit when DNSSEC is enabled. 2.1.2 ============= FEATURES: - NSD now fully supports unknown record types using the notation specified in RFC3597. - Support for the following RR types has been added: WKS, X25, ISDN, RT, NSAP, PX, NAPTR, KX, CERT, DNAME, and APL. DNAME special processing is not supported. BUG FIXES: - Bug #84: NSD now uses SIGUSR1 instead of SIGILL to report stats. - Bug #85: Support for WKS records. - Bug #86: The characters "#%&^[]?" can now be used without backslash in zone file domain names. - Plugin callback return type fixed. - The maximum message length for IPv6 UDP packets is now limited to the IPv6 minimum MTU (1280) unless the IPV6_USE_MIN_MTU socket option is supported. 2.1.1 ============= BUG FIXES: - Bug #81: Handle unknown types correctly. - Bug #82: Zonec: don't report "0 errors" unless -v is specified. - Bug #83: Close zone files after parsing. - Handle AFSDB RR type. 2.1.0 ============= FEATURES: - New networking code allows a single server to handle both UDP and TCP connections. By default up to 10 simultaneous TCP connections are supported. Use the '-n' flag to change the default. 2.0.2 ============= BUG FIXES: - Allow the use of a mnemonic for the algorithm field of a DNSKEY record. - Behavior of the zonec -v flag has been modified. By default zonec will only print a single line with a summary of the error count. - Bug #75: Fixed typo in previous "fix". 2.0.1 ============= BUG FIXES: - Queries for QTYPE DS (DNSSEC) were not handled correctly in certain cases. - Partial support for unknown RRs. Known RR types with unknown RR data format is not yet supported. - Bug #75: Fixed bad error message when nsdc update is run for the first time. - Bug #78: Multiple zones, each with include directives, are now compiled correctly. 2.0.0 ============= FEATURES: - Experimental DNSSEC support implemented, but disabled by default. Enable using the --enable-dnssec configuration option. - IPv6 enabled by default. Disable using the --disable-ipv6 configuration option. BUG FIXES: - Bug #47: Domain name is now logged when a notify is received. - Bug #70: First include all A records in the additional section, followed by AAAA records. - Bug #77: Check length of domain name and label. - LOC records are supported again. 1.4.0-alpha1 ============= FEATURES: - New database format that is much more compact and portable across architectures. - The new zone compiler is now the default and the old zone compiler has been removed. - Name compression is done dynamically, removing one other difference with BIND in the responses generated (the full query name is now used for compression). - CNAME target records are now generated from wildcard records if necessary. REGRESSIONS: - mmap(2) isn't currently supported. - Not all RR types are supported by zonec (such as LOC). 1.3.0-alpha1 ============= FEATURES: - New name lookup algorithm. This required a change to the database format. Performance should increase at the expense of database size and memory usage. - New zone compiler (zonec2) based on flex and yacc, fully RFC compliant (still in alpha). - Database can be loaded using mmap(2) (use the --enable-mmap configure option to enable). This is useful on operating systems such as Solaris that do not allow memory overcommit. - Region based memory allocation and resource management. - New internal format for storing domain names. Each dname now includes an array of label offsets within the domain name. - Updates to the plugin API. BUG FIXES: - Bug #65: The syslog facility is now a compile time option (--with-facility=FACILITY). The default facility is DAEMON. - Bug #66: Automatic periodic dumping of the statistics (using the -s option) is now continued after a database reload. 1.2.4 ============= BUG FIXES: - Bug #72: If an RRset for a child domain is defined before the RRset of the parent domain the parent's RRset would be "lost". 1.2.3 ============= BUG FIXES: - Bug #65: The syslog facility is now a compile time option (--with-facility=FACILITY). The default facility is DAEMON. - Bug #66: Automatic periodic dumping of the statistics (using the -s option) is now continued after a database reload. - NSD would try to kill pid -1 on startup if forking of a child process failed. - Do not log EAGAIN errors on calls to recvfrom. These errors should be harmless. 1.2.2 ============= BUG FIXES: - Bug #59: NSD returns FORMERR when the query name is >= 246 bytes. - Bug #60: Zonec runs out of file descriptors with many zones. - Bug #61: nsdc uses /bin/sh hardwired (and should not). - Bug #62: NSD is not able to log to a file. - Bug #63: nsdc update and zonec are too talkative. - Bug #64: Answer for request of a host resolved by a wildcard-resource-record is not understandable by dig. 1.2.1 ============= BUG FIXES: - AXFR terminates early if a zone contains a CNAME pointing the the zone's domain name (SOA record) (bug #56). - During an AXFR memory above the top of the stack was accessed. This could lead to occasional AXFR errors (bad packets). - NSD now prints its version number and exits when invoked with the -v flag (bug #57). - NSD prints help information and exits when invoked with the -h flag. 1.2.0 ============= FEATURES: - NSD is now a single parent process (handling child termination and database reloads) plus multiple UDP and TCP child processes handling queries. Before the parent process also handled UDP queries. This change simplifies the parent and child processes and allows the use of multiple concurrent UDP servers. - Experimental plugin support. This required a minor, incompatible change to the database format. Make sure you recompile your database. Use --enable-plugins to enable. - Full IPv6 support (for multi-homing and for Linux, thanks to Colm MacCárthaigh and Jun-ichiro itojun Hagino). Use --enable-ipv6 to enable. - Support for multi-homing with TCP connections. - Support for SunOS 4.x has been dropped. CODE CHANGES: - NSD should now conform to the Single Unix Specification (http://www.unix.org/). - Const correctness for strings and some other data types. - Removed code for Berkeley DB, hash tables, and mmap(2). - Separate preprocessor flags from code flags (CPPFLAGS and CFLAGS). - Use uint8_t instead of u_char, uint{16,32}_t instead of u_int{16,32}_t. - Fixed warnings from mixing signed and unsigned types. - Use sigaction(2) instead of signal(2). - The query_process function has been split up for clarity. BUG FIXES: - CHAOS TXT queries failed on big-endian machines. - Portability fixes for Tru64 (thanks to Stephane Bortzmeyer), HP-UX, and MacOS X (thanks to Ronald van der Pol). - Removed compile time limit on maximum number of TCP child servers. - Support for debugging UDP and TCP queries. - Always ensure there is enough room for the EDNS record when answering a query with EDNS enabled. 1.1 ============= FEATURES: - ANSI C - autoconf/configure - new parser - support for various RR types in zonec - support for UNKN RR types BUG FIXES: - lots of zone parsing errors eliminated - empty node matching bug gives NXDOMAIN 1.0.3 ============= This release is a bug fix release and does not add any new features. BUG FIXES: - Ignore SIGPIPE errors (bug #43). - Keep track of TCP child servers and restart if necessary. (bug #55) - Handle database reload failures correctly. - Close UDP sockets in TCP child servers. - Handle escaped characters (besides \.) in labels. - Preserve the query's RD flag in the answer. 1.0.2 ============= FEATURES: - -DBIND8_STATS to enable bind8 like [NX]STATS - -t flag to make nsd chroot to a certain directory - -s flag to make nsd produce statistics every s seconds - /etc/nsd/nsdc.conf to overwrite default variables for nsdc.sh - less loggin and more radical tcp connection (mis)handling - prefork -n processes to handle tcp connections - multiple -a flags CHANGES: - named.stats file functionality is removed BUG FIXES: - couple of pedantic fixes in C code - last zone in database axfr bug fixed - nsdc update wont update bug fixed 1.0.1 ============= FEATURES: - NSD drops permissions after binding the sockets - ``cache'' zones are no longer allowed - ID.Server & Version.Server compile time options - AXFR implemented (with tcpwrapper for access control) - nsdc update and nsdc notify functionality - using named-xfer with TSIG for inbound axfr CHANGES: - the order of records in the database is from now on significant - since Berkeley DB doesnt define order for sequential access it is no longer supported BUG FIXES: - white space problem in zonec is fixed KNOWN BUGS: - please see appropriate man pages for the known bugs 1.0.0 RELEASE ============= KNOWN BUGS: - Although NSD allows one to configure a zone without SOA record and use it as so called ``cached'' non-authoritative data, it is decided that having this functionality is wrong, dangerous and will be removed from the further versions. - If while processing EDNS(0) OPT record NSD encounters bad EDNS(0) version it will answer with Format Error instead of EDNS(0) BADVERS PLATFORMS: Tested and working on i386 FreeBSD-4.4, i386 Linux, dec alpha Linux, sparc SunOS 4.x 1.0.0-BETA2 =========== FIXES: - wildcards bug fixed - AA bit for class ANY bug fixed - minor coredumps with really broken zones in zonec fixed - linux & SunOS port 1.0-ALPHA2 ========== FIXES: - IPv6 transport support added by Jun-ichiro itojun Hagino (Use -DINET6) - Makefile modified for easier compile time configuration - EDNS(0) bug fixed - Default database changed to all lowercase, red-black tree to make nsd DNSSEC ready - REQUIREMENTS are cleaned up and updated - Signal names changed in nsdc.sh.in - Default compile options dont include -DMIMIC_BIND8 nsd-4.1.26/doc/README.svn0000664000175000017500000000174510542235616014273 0ustar wouterwouterIf you build NSD directly from the Subversion repository, you will need the (gnu) autotools to generate the configure script. On most systems, this can simply be done by using autoreconf: autoreconf This will call autoconf, autoheader, aclocal etc. After this you can build normally with configure and make, see the general README for further information on this. Some systems do not have a symlink to separate versions, so you will have to use the specific version name. It should work with at least 2.53 and 2.59. The actual executable name may differ on various systems, most of the times it is either called autoreconf-2.59 or autoreconf259 Some systems also do not have a standard aclocal link, in which case you will have to tell autoreconf what aclocal executable to use. This can be done by setting the ACLOCAL environment variable. It should work with aclocal 1.4, 1.5 and 1.9. Examples of complete commands: ACLOCAL=aclocal19 autoreconf259 ACLOCAL=aclocal-1.9 autoreconf-2.59 nsd-4.1.26/doc/NSD-FOR-BIND-USERS0000664000175000017500000001541012623035675015211 0ustar wouterwouterNSD for BIND users ------------------ Contents 1. Zone compiler. 2. Authoritative only. 3. Config file format. 4. Keys not per IP address. 5. NOTIFY of NS-entries. 6. Less options. 7. Master-Slave meshes. 8. AXFR behaviour. 9. Ports. 10. nsd-control setup Please see the README for general information. This document assumes the reader is familiar with BIND tools and explains the differences between BIND and NSD. 1. Zone compiler. In its memory NSD maintains fragments of data that are ready to put 'on the wire' without a lot of additional work by the server. Those fragments of data need to be compiled from the zone file. Therefore NSD has a zone compiler that translates the text format zone files into a binary format database file that the server reads. 2. Authoritative only. NSD only serves authoritatively. So, NSD does not provide caching, and does not provide recursion, or resolver functionality. NSD can, in other words, function as master or slave server. This also means no root zone '.' type hint is used; leave out the root zone entirely from your configuration. NSD does not cache the root. NSD will not provide an upward referral in case an authoritative answer cannot be found. Because of this design choice (see Appendix B.1 of the REQUIREMENTS file) NSD does not need to maintain knowledge of the root-server set and there is no need for a root.hints file. Also leave out localhost zones from NSD config. 3. Config file format. The config file for NSD nsd.conf(5) is different from BIND named.conf(5). See the manual pages for differences in syntax. The zone files with resource records have the same format however. A short configuration file for BIND can look like this: // Name server configuration named.conf options { directory "/etc/dns"; pid-file "/etc/dns/pid-file"; dnssec-enable yes; listen-on-v6 { any; }; recursion no; }; // logging options for the DNS Server logging { channel mainlog { file "/var/log/dns.log" size 10m; severity info; }; category default { mainlog; }; }; // root hints zone "." IN { type hint; file "root.servers"; }; zone "localhost" IN { type master; file "localhost.zone"; allow-update { none; }; }; zone "0.0.127.in-addr.arpa" IN { type master; file "localhost.rev"; allow-update { none; }; }; // authoritative server for example.com zone "example.com" IN { type master; file "example.com.signed"; }; The equivalent configuration file for NSD is shown below. Note no ;s at the end of statements. No braces {}, and comment is with #. # Name server config for NSD, nsd.conf server: zonesdir: "/etc/dns" pidfile: "/etc/dns/pid-file" # dnssec is automatically enabled in NSD for signed zones. # ip6 is also enabled for NSD. (ip4-only: yes to turn off). # NSD does not do recursion. database: "/etc/dns/nsd.db" # logging clause comes here, no size or severity options. logfile: "/var/log/dns.log" # NOTE: no root hints. # no localhost, and no 0.0.127.in-addr.arpa zone. # authoritative server for example.com zone: name: "example.com" zonefile: "example.com.signed" 4. Keys not per IP address. BIND associates TSIG keys with an IP address. When communicating from/to that address BIND will TSIG sign. NSD associates TSIG keys with the acl entries, when performing these functions NSD will sign with TSIG. It is thus possible to configure NSD to use a different key for notifications then for zone transfers, and a different key in one direction from the other. Additionally, NSD will reply TSIG signed queries with TSIG signed responses. In BIND you might have a master that uses tsig for zone updates. // ... rest of named.conf config file // the TSIG key shared secret with the slave server key key23.example.com. { algorithm hmac-md5; secret "6KM6qiKfwfEpamEq72HQdA=="; }; // when BIND communicates with this server, use the key server 168.192.0.15 { keys { key23.example.com.; }; }; zone "example.com" IN { type master; file "example.com.signed"; allow-transfer { key key23.example.com.; }; }; For NSD the master configuration would look a little different. # ... rest of nsd.conf config file. # The TSIG key shared secret with the slave server key: name: "key23.example.com." algorithm: hmac-md5 secret: "6KM6qiKfwfEpamEq72HQdA==" # no need to list the server { keys { keyname; }; }; statement zone: name: "example.com" zonefile: "key23.example.com." # the allow-transfer and server statements from BIND rolled into one. provide-xfr: 168.192.0.15 key23.example.com. # # since NSD does not send notifies to the servers listed in the NS rrs, # the above server must be explicitly named to get notify messages. # see item 5, below. Note, the keyname is repeated here. notify: 168.192.0.15 key23.example.com. 5. NOTIFY of NS-entries. BIND sends notification messages automatically to the servers named in the SOA and NS entries of a zone. NSD does not. It sends only to the 'notify:' entries in the config file. If you want NSD to send notifications to these servers, include notify: statements in the config file for them. 6. Less options. NSD has less options than bind has. It is designed to be small. Some options that are *not* available in NSD are: provide-ixfr trusted-keys {} controls {} logging options lwres {} rrset-order recursion yes; cache options zone types: hint, forward, stub view clauses 7. Master-Slave meshes. NSD can be configure as both a slave of a (hidden) master and as a master to further slaves as well. This way meshes of name servers can be created, like with BIND. 8. AXFR behaviour. To do a manual AXFR, nsd-xfer will perform like the BIND tools. But, the initial query for the SOA is done by TCP, where the BIND tools use UDP for that SOA query. According to RFC (1034, 1035) specs, both UDP and TCP for the initial SOA probe are OK. An AXFR initiated by the built-in transfer process will not start with a SOA query at all. The first packet of the AXFR transfer will be used to determine the SOA version number in that case. This is a conscious breach of RFC spec to ease implementation and efficiency. Note that usually the built-in transfer process will request an IXFR, and preceed the IXFR with a UDP IXFR request like the RFC says. 9. Ports. Nsd can be configured to run on another port than port 53. See the 'port:' statement in the nsd.conf file. Access control list elements can be appended with @port_number to refer to a specific port only, such as 10.11.12.100@8853. NSD will not set its source port for outgoing connections to be equal to the configured port, ephemeral ports are used for notify, ixfr and axfr requests to other servers. 10. nsd-control setup The rndc tool for BIND named needs a secret to communicate securely with the server. The NSD tool nsd-control can setup its secrets with the nsd-control-setup command. It uses public keys, and SSL connections. nsd-4.1.26/doc/NSD-DATABASE0000664000175000017500000000176711542666625014334 0ustar wouterwouterNSD 4.0 DATABASE FORMAT. The NSD 4.0 database format is different from NSD 2 and NSD 3. It stores RRs, but in a way that they can be edited without leaking space. The file contains a 'buddy-system-style' 'malloc' of chunks. Pointers are offsets from the start of the file. For every pointer the reverse is kept track of, so that chunks can be moved to a new position. Free space is reused, and (gradually) moved to the end to shorten the file. It is about 23x larger than the NSD3 format and about 3x to 6x slower to read and write a full database. But you can use a tree to fetch a particular item at log(N) cost, and update a single item at log(N) cost. Therefore, adding a zone or removing a zone does not need a new compile of the nsd database, but can be performed by editing the database. The file format is endian-dependent, and uses 64bit file offsets. The file chunk format is defined in udb.h. the tree for lookups is defined in udbradtree.h. The rrsets and zone format is defined in udbzone.h. nsd-4.1.26/doc/TODO0000664000175000017500000001604112623035675013276 0ustar wouterwouter$Id: TODO 4553 2015-11-18 08:50:05Z wouter $ AUTOCONF - check/translate arguments to --with-facility ZONE COMPILER - unify dns type table (name, dns type, yacc token, rdata types) prettier? - unify dns class table (name, dns type, yacc token) prettier? - one db file per zone (as an option?) (featurecreep)? req by Alex (Bit). So that after rsync, zonec is fast with many zones. - if a zone is dropped from the config file, but not removed from the nsd.db. NSD refuses to start. Should skip/drop the zone. Redesign file format, so that you can skip a zone more easily, this also makes multiply db files easier. - profile the zonec compiling speed. Speed it up. Many people complain about this. - wireformat interop. testing for IPSECKEY type. - chown nsd nsd.db (Paul Wouters nsd-users mail) SERVER - make sure that we dont copy anything from the query we dont want to copy, like funny headers etc - From Aaron Hopkins: set O_NONBLOCK on all sockets. Now a udp raging herd of server can get woken up when a message arrives. One server handles the packet, the rest blocks on that socket and does not serve other sockets. - From Aaron Hopkins: write tcp length and tcp data in one write operation, instead of multiple calls to write. Avoids Nagle algo delay in this case. preallocate 2 bytes in front of buffer to put them into. - Test TCP performance (do a lot of AXFRs, different zone sizes, and compare time averages). - From Aaron Hopkins: after you do select calls, do multiple read calls per select. This polling improves performance in high-load situations. Speed test to prove that it does so. - Turn off TC bit on all error replies. - Bug #133: print empty statistic blocks. Not sure if the feature is wanted. - XFRD should throttle the number of notifys going out for a zone to x/minute. (even if updates are very often). - Option to only notify a batch of slaves (from loads) at a time, with timeout between. - Round robin selection to send notify to secondaries. So the last one on the notify list does not diverge. - xfrd NOTIFY timeouts exponential backoff. - query SOA before getting AXFR and then cutting it off, it causes an errlog on the master. - when verbose, print the ip addresses that cause network errors to the log. - the server reaps children every minute, this is bad for powersaving laptops. - Implement AXFR clarify, RFC 5936. SECURITY PURITY - some data is in network order some in host order, make it clear with prefixes prettier? - brush up the function and identifiers names - The XFRD zone state can be split up in expired/service-possible and in idle/zone-transfer-busy state flags. Is this more beautiful? - no more #ifdefs, remove them all, but keep configure options. - getflags on socket before setflags nonblocking. - exponential backoff for retries xfrd and notify. - conformance to RFC: NSD accepts TSIG before OPT in additional, but this is not legal, only TSIG after OPT is allowed. - Allow for username: uid:gid, next to uid.gid. - Log error when serial in xfrd.state is inconsistent with that from nsd.db. NSD PATCH - -q(?) option: no output when no patch necessary - cleaner output on normal operation (don't mention memory) - patch on demand after a xfrd reload has occurred (including checks for disk memory and a reload timeout (no more often than 15 minutes or so)?). CLEANUP - make so that startup sends SOA_INFO to xfrd just like reload does, prettier? - dlopen and dynlib checks can be removed from autoconf scripts. - If presentation format NSEC3 stays, put optout-iterations into one 4byte datatype, easier reading and printing, avoids ugly special cases. DOCUMENTATION - document what to do when adding (or removing) a config option (what changes have to be made in the code). OPTIMISATIONS - delete entire zone for AFXR during reload read in, now walks the tree, but could use a double linked list to speed up. - less memory churn in deleting RRs/adding RRs: keep rrset->capacity num. initial read in capacity==limit, if you want to add RRs, alloc capacity*2. - less memory churn in deleting rrsets : keep a linked list of deleted rrsets for reuse. Keep a list (based on buckets of size of the malloc) of rr arrays. Keep a list (based on buckets of size of malloc) of rdata arrays. Keep a list (buckets on size) of rdata_data allocs. For reuse, buckets on char size, because we know most are small anyway large ones can be discarded/churned. - Look for special purpose memory allocators for NSD. - compress dnames in ixfr queries (write_soa_buffer) (zone 2x, mname, rname). small gain, nasty code. - compress dnames in tsig records, keyname, algorithmname. - compress names in packets by pointing to uncompressed_dname entries. After each DNAME(with uncompressed target) follows a CNAME that can be compressed in this way. - Do not give servfail during reload quit sync process. Only stop old server processes once the new ones are forked and answering for secondary zones (so when xfrd is done with sending zone state to all children). The brief double answers are preferable to brief SERVFAIL. - nsd manual programs contain identical functions that are written down multiple times. Do we need to introduce a util_programs.c or something? - reduce the memory leak on zone transfers (deleted domains are not removed from tree). - Options server: ip-address: and zone: outgoing-interface are pretty much the same. - Options to make NSD restrict AXFR response messages to a single RR (RFC5936) TESTS - tpkg test for bug 157: a valid NSID EDNS0 option generates FORMERR on nsd-3.0.5 - tpkg test for bug 163: unable to read nsd.db when chroot'ed - tpkg test for bug 164: chkconfig - Update tpkg long tests - tpkg test for bug 347: NSEC3 no data tests when requesting DS From tpkg/bugzilla-bugs todo: ! - other ways to test this? ! 3 "RCODE for dynamic updates" --- how to send dynamic updates? ! 20 "256 questions per-se should generate form err" ! 22 "trailing byte in queries (see also bug4)" ALLOW TESTING WITH TRACES ! 31 "query section not included in 'NotImp' answers to updates" ! 37 "invalid packet echoed on FormErr" - how to send stuff with tcp replay ! 100 "zonec alters RRSIG inception/expiration" on sparc only --- hmmmm ! 29 "NSD sends answer on notify" - cannot send notify with DIG M - Moet nog M 157 "return FORMERR if edns query is received with version=0 and rdlen>0" M 163 "..." M 164 "chkconfig" - - too little information to write a testcase - 4 "Correctly handle queries with too much data" to little info - 6 "different name encodings?" - 7 "sometimes label compression skip some parts" - 8 "do not exit on sendto buffer exhaustion" - 10 "Segmentation violation while trying to destroy the database on exit" - 11 "EDNS(0) spurious formerr" - 14 "Magic string alignment" - 15 "nsd hangs on some queries..." - 16 "zonec dumps core with HASH -z nl nl -c . examples/zones/root" - 18 "name compression not quite 100% yet" - 28 "Wrong additional section RRcount in case of EDNS." - 35 "sending wrong name errors (NXDOMAIN)" - 36 "we should not bounce on RR Type when doing a referral" nsd-4.1.26/doc/differences.pdf0000664000175000017500000150764110522345635015566 0ustar wouterwouter%PDF-1.4 5 0 obj << /S /GoTo /D (section.1) >> endobj 8 0 obj (Introduction) endobj 9 0 obj << /S /GoTo /D (section.2) >> endobj 12 0 obj (Response differences between BIND 9.3.2 and NSD 3.0.0) endobj 13 0 obj << /S /GoTo /D (subsection.2.1) >> endobj 16 0 obj (Comparison of responses to root queries) endobj 17 0 obj << /S /GoTo /D (subsection.2.2) >> endobj 20 0 obj (Comparison of responses to NL TLD queries) endobj 21 0 obj << /S /GoTo /D (subsection.2.3) >> endobj 24 0 obj (Features) endobj 25 0 obj << /S /GoTo /D (subsubsection.2.3.1) >> endobj 28 0 obj (n-clrdobit - NSD clears DO bit in response) endobj 29 0 obj << /S /GoTo /D (subsubsection.2.3.2) >> endobj 32 0 obj (n-clrcdbit - NSD clears CD bit in response) endobj 33 0 obj << /S /GoTo /D (subsubsection.2.3.3) >> endobj 36 0 obj (b-class0 - CLASS0 formerr in BIND) endobj 37 0 obj << /S /GoTo /D (subsubsection.2.3.4) >> endobj 40 0 obj (n-tcinquery - TC bit in query is formerr for NSD) endobj 41 0 obj << /S /GoTo /D (subsubsection.2.3.5) >> endobj 44 0 obj (b-soattl - BIND sets SOA TTL in authority section to 0 for SOA queries) endobj 45 0 obj << /S /GoTo /D (subsubsection.2.3.6) >> endobj 48 0 obj (b-classany-nxdomain - BIND gives an auth answer for class ANY nxdomain) endobj 49 0 obj << /S /GoTo /D (subsubsection.2.3.7) >> endobj 52 0 obj (b-badquery-badanswer - BIND replies with bad answer for some bad queries) endobj 53 0 obj << /S /GoTo /D (subsection.2.4) >> endobj 56 0 obj (Functionality Differences) endobj 57 0 obj << /S /GoTo /D (subsubsection.2.4.1) >> endobj 60 0 obj (d-notify - different NOTIFY errors) endobj 61 0 obj << /S /GoTo /D (subsubsection.2.4.2) >> endobj 64 0 obj (n-update - NSD does not implement dynamic update) endobj 65 0 obj << /S /GoTo /D (subsubsection.2.4.3) >> endobj 68 0 obj (b-mailb - BIND does not implement MAILB) endobj 69 0 obj << /S /GoTo /D (subsubsection.2.4.4) >> endobj 72 0 obj (d-version - BIND returns servfail on version.server queries) endobj 73 0 obj << /S /GoTo /D (subsubsection.2.4.5) >> endobj 76 0 obj (d-additional - Different additional section on truncated answers) endobj 77 0 obj << /S /GoTo /D (subsubsection.2.4.6) >> endobj 80 0 obj (d-refusedquery - BIND includes query section in REFUSED answers) endobj 81 0 obj << /S /GoTo /D (subsubsection.2.4.7) >> endobj 84 0 obj (d-hostname - BIND adds a NS record for hostname.bind) endobj 85 0 obj << /S /GoTo /D (subsubsection.2.4.8) >> endobj 88 0 obj (n-ixfr-notimpl - NSD does not implement IXFR) endobj 89 0 obj << /S /GoTo /D (subsubsection.2.4.9) >> endobj 92 0 obj (d-formerrquery - BIND includes query section in FORMERR answers) endobj 93 0 obj << /S /GoTo /D (subsubsection.2.4.10) >> endobj 96 0 obj (d-badqueryflags - BIND includes query section in FORMERR answers) endobj 97 0 obj << /S /GoTo /D (subsubsection.2.4.11) >> endobj 100 0 obj (d-unknown-class - BIND includes query section in answers to unknown class) endobj 101 0 obj << /S /GoTo /D (subsubsection.2.4.12) >> endobj 104 0 obj (d-unknown-opcode - NSD returns NOTIMPL for unknown opcode) endobj 105 0 obj << /S /GoTo /D (subsubsection.2.4.13) >> endobj 108 0 obj (b-upwards-ref - BIND returns root delegation) endobj 109 0 obj << /S /GoTo /D (subsubsection.2.4.14) >> endobj 112 0 obj (b-noglue-nsquery - BIND returns no glue for NS queries) endobj 113 0 obj << /S /GoTo /D (subsubsection.2.4.15) >> endobj 116 0 obj (d-noquestion - different error on no question) endobj 117 0 obj << /S /GoTo /D (subsubsection.2.4.16) >> endobj 120 0 obj (b-uchar - BIND returns FORMERR on strange characters) endobj 121 0 obj << /S /GoTo /D (section.3) >> endobj 124 0 obj (Response differences between NSD 2.3.6 and NSD 3.0.0) endobj 125 0 obj << /S /GoTo /D (subsection.3.1) >> endobj 128 0 obj (Comparison of responses in root trace) endobj 129 0 obj << /S /GoTo /D (subsection.3.2) >> endobj 132 0 obj (Comparison of responses in NL TLD trace) endobj 133 0 obj << /S /GoTo /D (subsection.3.3) >> endobj 136 0 obj (Version number - version.bind and version.server) endobj 137 0 obj << /S /GoTo /D (subsection.3.4) >> endobj 140 0 obj (n-notify - notify not implemented in NSD 2) endobj 141 0 obj << /S /GoTo /D (subsection.3.5) >> endobj 144 0 obj (n-ixfr - IXFR error FORMERR in NSD 2) endobj 145 0 obj << /S /GoTo /D (section.4) >> endobj 148 0 obj (Response differences between BIND 8 and NSD 3.0.0) endobj 149 0 obj << /S /GoTo /D (subsection.4.1) >> endobj 152 0 obj (Comparison of responses in root trace) endobj 153 0 obj << /S /GoTo /D (subsection.4.2) >> endobj 156 0 obj (Comparison of responses in NL TLD trace) endobj 157 0 obj << /S /GoTo /D (subsection.4.3) >> endobj 160 0 obj (b8-nodata-ttlminup - BIND 8 uses minimum TTL from SOA also if bigger) endobj 161 0 obj << /S /GoTo /D (subsection.4.4) >> endobj 164 0 obj (b8-badquery-ignored - BIND 8 replies normally for some bad queries) endobj 165 0 obj << /S /GoTo /D (subsection.4.5) >> endobj 168 0 obj (b8-badedns0 - BIND 8 ignores bad EDNS0 queries) endobj 169 0 obj << /S /GoTo /D (subsection.4.6) >> endobj 172 0 obj (b8-auth-any - BIND 8 includes an authority section on queries for ANY .) endobj 173 0 obj << /S /GoTo /D (subsection.4.7) >> endobj 176 0 obj (b8-ignore-tc-query - BIND 8 ignores the TC bit in queries) endobj 177 0 obj << /S /GoTo /D [178 0 R /Fit ] >> endobj 181 0 obj << /Length 1182 /Filter /FlateDecode >> stream xÚ¥VYoÜ6~ׯУD ïÃO©±MaÃ0àîšäa9Q •Ö’Ö®ûë;CRZ5QÁ+’3œ{¾!K)üXÊ(%Bj™- çT¥ûcBÓ/@ü#a‘©°œh¦X* ÕÒ"Kú”Rb´g˜pþ4]ŠooŽ,]µÉC’>L4PH˜²&-.P*-#Ö¥ÅܲëMòö=²!œ)™ng0E$a›ÃÇìϲ?å… YÛô%,´ÉVÕ'ÊDÎ2س¬+›}Ù#Eg;øÀñÿ þ•e“Þ܂ӄ;„Þ¯ñæ*ˆÛ6‡°h‡¯eUÜ#Ã:lÖe÷\v= ›!ÔŒ8¥8ÚÌ9qL‚ÌI¹ðÒo½]õ€ærÝân æ6¸èƒE È¥†8CÊQŽ(a”D+½”O”Š%•c=q½ ,BÍY äD`&½¯w^/Å[s‡–ì¼%KÒ ­‰àHÁ £ êe|È9„.žñ‡Ç@Áá‡êÛèÙXl·ÈÙÁê0W1wÕ b•“sW_ÅOó“~2 FuÞŠ‚qA7:js£/@ÈìÝÙåxßïm^p›íÏGŸÞ&Ç@x §T”ÊÅqPûÂñÑÈö¹<î¼ Añ7ñKA"Õ($ù}3uÏÔšƒ$°:4çÇÏ4=@«Ý&@vV¥/ ö/s ê˜è8%!Xñ¤NÖÉì¡ Ž.ÿº$¦!ˆVCoKý/ļÿÀ®1¡ÀT@]¡ì€à’®f°éȆ‘ûm×綠übNá¢äUŠ(*Cél¾Â… ³¨dÖ´¾-•‚Òï=Œ SÌLämw}@˜çòNðN¬4<¡Â<µj·›$Ÿ¼¼¶ UÄ&ÉQÏ€Íò’ãÒSãýûõ*,†#HÀý€BëºÂy#‡ zʶ~ý§< O‚ØH©ÐðaÒÔž"dxP«êj@¯÷”s—uí®.c1 1&)lÛ³7‚ü/º0˜dZ›¥ùMSN”£?ŒSfI-±4>.†›%NkÿnPaˆã0Wh@ñoe=Í)\¼kê¦OÍF¨Ùô#¡¤ÿ†bg0ñ ¸2q‚º‚ª°§îJÙ+iþ Œð”ã>´Ö¾ c|^Îü£ô/Y<‡endstream endobj 178 0 obj << /Type /Page /Contents 181 0 R /Resources 180 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 190 0 R 197 0 R 204 0 R 208 0 R ] >> endobj 179 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/wouter/texmf/tex/latex/LogoInGradientBar2.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 216 0 R /Matrix [1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000] /BBox [0.00000000 0.00000000 703.00000000 64.00000000] /Resources << /ProcSet [ /PDF /ImageC ] /ExtGState << /R7 217 0 R >>/XObject << /R8 218 0 R >>>> /Length 219 0 R /Filter /FlateDecode >> stream xœm˜[ne» DÿÏ(ö¢èMé?H~2¹ `'èdþ@VQÚ÷ñmàÚ¢õ$‹ÅâþuÄŽ¨ûçÇ×ëϳãÿ½~½âQj iÎã륿}¾,¦júöû9çóõ÷ã߯_ö´æh} 9¦ãO1´sÓ/uÎ:Ó:hùÏë¯üûåè˜^¦ožçóWøO?€‹–RØS[¶Ñø[(3Çyü÷W:þõê©öí(c„Î=¾^=Ú å¶|¾Úl1Ä|´l,~Zs†µÐÛ–^Fˆ©ûªšCy8*ép†o|Zsöß-÷Qÿxñx ==Ÿ‘ãueá5ìL21ëVràUUÄR*ãšüïÅB®mk)tvÅyN·žÃ(Gå|¹¬9Lα¬8îCXÔ–,„gúÀ¸GGî矼0»8ªå[ʼnTÓ¸”`œÄÈEæ´Nu—¡­Xa#/Žb…@fdR»†ZÀDåžœMã¹¢ÆÿÂä.Â4¹_âJîUc[†LÚû!ŠèB@ówæ\|E=óR.¯Ä ò\Ÿpà œ|ŠîìÓÂc¢&¬ ZjĽ]G(e)¾`]¢Q4ZRtIf´øÓz…òŸ#‰œ¿[ï„B,®k»Ê=9JgÞè4ÎE÷Œ×i1ˆ[S4!DñLÐ(€oƒÌQ´¸ï¨çBañè J ÜæD€e§%ô eñ@qÌlh›9L?ÞÀ®rÆÅÒò^wòûº,âŸ)"1åK_T•òB‰nçm‡G¨’•|ïkE9ßL09ÇZAxg}Ìàu ‰vp`ÔÏHݓלkýQ—È×%ùýŸÏøx{˜²2{R`ʼnüü’…Èa€Ÿ¦dÒ0‡É-Ê—Íñ=§gÀÄ­zÊD¶Oy÷Α>»þÌ™)ì<’jpV… òlva—–¥m2PjwCrüdÁoJ,øŠkóù^î’´Ï»åænÞ_œ5ß-÷Yçª7K%Îqäojou?À‰$vkWÆÙblžR³+ûÈs/Û ½æÖº¼À¯iL!kQ°¡H½XŸª¦ñ¦Ì)»†Z§ÞwIHTÈš8¡P뢮7p0®J%êz&=aJ|,J"‰xàiù¼,M…îVa”:µ,A"Ø~ž¿î})RÍÀÊ‘Dþ~öã¹ô>Ïq™•ÎAÉpTcP¢qsaµÇ*¶"£ÇøZU_©úÖã 0'ûûµ½Öº$“Ë«Âã%2‚’’F‘!eÈ8ŠË¨^žD”Ð"¿ʵT%ñ~ë:5ŽC´î,1À5ϱë2®™3Câñ¼7¡EeQ9b«,xyÞ3\Û½C3ýy„¨Z¾'+@2ô*d}¯hk8Žmá8¯O*U 8»ª’¬B¾‹f€·}¡ñŽT÷ËbÞ¢è v «ݩ̀€µÍâT§$± §‹ê*©ÁRR)Õx¸\M¢-¹±!€l,ž–¶hêa»È9µB Ÿ‰Õ«~¹†º"…ZwOJÆ·  µ¢g$enêr¶-׸…>(¬¶CÉM²4¤$Y…eðQV jË]8cÖUµåžQŒ¨_tZ’É<ä|ÒˆÄ>,šUœ0T’ “ì^F[wñŸ%“–t'ò¦Ôñ”ÔOñ,ª…¨Œq÷ñ¸*Oƒâeq¦×–+»ügÇ÷äüPIÝ®&ŠCùôu;?/_¹B*‰‰}ñw.ð“ëwEYÀ¡ê%á»áÈœ^”=>>qxSÏQž³¡»ÆªG»®lKSéu š÷0`RVw)q0@íKZ jHE„-ïÓ%D<=ýÌ/Òâ{ÁêšÑÈÎ&Q Æ[>~÷͇wy4ÄêA®¤Žz™¹nK†‚¨1®Êé1Š QV¤] ô:Æ®ý‰-³ìh¼&àðáà\rÈ 8ÕÎÒÝ{&ÉÅ7dj–²ÅeLj;Ï1“bã+–…C;¨&ÙºT½Z:Õ B¶HјŠë“ªž.aôªù¦#½i–'a™ÚÁkR(ƒHµ:Ûà&¢ê¤wcÅÊ (ѺZSRJ9HŸi :_¸?ÞÂá*q»?‘xâŽèr÷|X/è¿=_‘®Ù\ì’î{—ñ{¹ÛÔw“ë&á ‚ùËv´{ 0iÁô›ª`»»÷8Á×ÛBvV—l \V7¡of^t”ÛJf­èÞW‰ÊPK³>\4hÅûƒ(ÕÔ“ª}(c1Êj/ž¾sÄH¹«N“¤“?·Ån©0 Z]™9žÏÆJJÞ]hª$£ i‹ûê ¦žíîŒY½Ö¤Î$¯L¾eŸ$¡>¹ä«¬C.‰®ìN á¬Uĥђ>МmMÕשàÕ«ßäÂjc°J†žc‰¹Uü¶ÁΘNZ(øÀôÙ§zy#¯ üˆÅk}§Ää0`87+ù3D“)¬®~¦ *Ñ•Ÿš»¸™šÚ!©ÎU’õ¥d(èÊcé5e©)…àf÷Ø[̽bY¦H[‰,-§ Ž,Ru9_o¦>6Q§‹Kª™³òòâ}³«ß*Ÿ|ócüß’W>éSZO§ÌFqt׫Ëâui‘äi•ì²(V2¾êÅÐÔ”žcªoù1C¥ZžûÜ»It'õGûžYÚ1Íì‡â}oÜÒØÍá5NçW—Ó¢ÂäÀeI*ó†˜!‡ï)Û‹§K+,®Ó× ¹Aó´ã ®UÙÇÖÓqÜ$IþFÏœÉíáH!¢-åïßÞä•WcÂ]$ŽäÊeѦú^矕 _ÑÇ ïµúª7VË;A,5¹éúÖû—ú`îY½{0÷,Þ!Ý3Ø /Í-æž­\–W–¥TfôO^ºŠ«§1†+6HÒ?;ýF""}Æþ? yˆendstream endobj 216 0 obj << /Producer (AFPL Ghostscript 8.51) /CreationDate (D:20060104161305) /ModDate (D:20060104161305) /Title (LogoInGradientBar2.eps) /Creator (Adobe Illustrator\(R\) X) /Author (Bert) >> endobj 217 0 obj << /Type /ExtGState /OPM 1 >> endobj 218 0 obj << /Subtype /Image /ColorSpace /DeviceRGB /Width 2921 /Height 143 /BitsPerComponent 8 /Filter /FlateDecode /DecodeParms << /Predictor 15 /Columns 2921 /Colors 3 >> /Length 203322 >> stream xœì½‡Ç•çÛ÷"çœ"ƒ9G1ˆT¢¤‘eËr’wïóy;o÷íìììzfvdkd[–,Ù%R"ÅœI0€$ˆD rîûUîsOW7/ ‘6Ë3ÔEߺuª«O:UõíS¡h4j}‘uÿ7„ÿùfņBóæ‰Š¢B ¾Ùæ¢s,2A•åSJâlHá„ð|EÍEY\ÈWâ\TfE©^ȃä+qfn–ÿL G|%ÎÌͰÄp(Á·b³s¨Õ5î.!!ä›mfvFgŠRå‘Ç[]«˜DÜbbBØÛþ¨ùìܬ-Q·ƒ·þønzvZ·ILˆ$„Þ¦@ͧUÅætå-´UbB¢W"ò@âœ]”jÓ¤p¢÷!9£Ns¥$&û6²ÍÚU哽ZqãÓ“ügFrš·(¤©™é©ÙiúŒ»KMLñæAs!Ïìì¬å¨ *æ½GHšà?³RÒ½E¡¡& ¯Ÿ#bJ$ÙÛªHƒã#ü9=95â«89f9]('5Ó›Í5139£7êŒVÅ=úJ¼?6ÄŸ3“Ó"^•ˆFѤü¸uå“’">ÏqhbzHŸS“}[©t͚˷AÜЄÝÈ•’á[ÔàÄrêZZiI)ø?oT~rz’º-"jîÕ ÜãÈä˜RW}ˆÊ'{îú0:5>=£$¢U¡Ì(Ê·Uï÷óç¢ÌH¤ÏÙ©Ù~ý-?:9N6'ƒ“”’£ZÕ¥9ˆÎ($&¢wø>îî¡{h|ý1ŠrrÒ²ü$Ž OŽÑs„IKJÍOÏöÞcßèà„’¨T:919;%Ã÷;{'»š›–•ë'©ùÞÙ˲‹Rý,9•mNj$¹,§È›+1>­ì*Z)5)¹83ß;ð!4‡I}ároQ¸Çîá¾ñ© Œ·Jbb Ú!Õc(Ðýï ³DX’’,‰cSwbšÓPTå•%D÷GN2˜(ÊWÁ M1¦ÇÕƒT¶ü°ŸÄÛ÷»øÏ•ÅÕ^‰Hè÷œÞ¢*óÊ|³]ín¡h´Ê¼Rßgî«¿“ÿ\]Rë[T[_'rÒçÂŒ\_+‡t¥ë&®Ê/ŸObk_‡]-ËZ[Vç[Të½;#ŽDˆƒJøf»ÔÙÄŸkò—Á®08vݰû#2 þÞ!JØ9xÝÖÒNBzRZYN¡¯‰¾Ðq?×TÌ×g»‡úè32ÔVøVþfïí=¸[ÚŒûZò®¡{ƒãÃäç ‹Áà”z²ÁöÞêï™ÄˆÙú»n;Cmvjúº²o(ó­û]äúb¨Â »êu}¡Ï}£ÔÓ“aÆs¼V÷íB4†¢kÀÊùzÈ:n 9ä(§ÊÏ`Þìmï¹?¡› =«òÍl‘m@ITc(dÕ.÷µçï\C6ú¼qÙJßZ5õÞ†ºÒP‹B „¹%FôÖ–¾Ž±!ºG”ÓPTé•+þ8¢;f.¹©™õ~­Š±ølûUþó¹;¼µBj¹w§µƒ»j/Ußg '¡ý~×°6&˜àeä"›wB‰§o_á?_Xù”¯Däa?åÀ®úfûíÕÏùóÖÊ5yi>úŒqöÔ-[b^ZֶʵÞ<ã×zZÉ‹F+¡_¬,®ñu`>h<ÊŸ·W®õö 8ƒÐ;H%P¥Êü2ïh… xÜŽÄzк²z_÷ø×W>ãÏ´f¯7$^ì¸Ñ768£gC¨R}a¥×ß³”]º—>#4Ç›½ìxëE6&_Yû´7¥Ž6Ð5žªÞà̓QºŠ¡7p½ 2²×”ÖyïNB×à=ò¾`— ó¾ †®}ýnKÜ]³Ñ›:ßÜÛNæ FÙ¼­ŠæÂ³FÝhP€©¬)¬XîéhHȆÿ£Ï\æó¾~qácú€FÛ[»©Àoà@¿þ¬ù,ÿùõ ÏyóÀ"]èl"GuF9«‹«½ 8 0†ƒÚ˜àái¯/÷±«ð ?½y†>cdyºn‹7,ÒÅŽëw‰…é¹–­ðŽ/Mwo·õw²Äòì"d3ò UOÞºÜ;ÒOSrH¬/ªDNO­ú¯t5÷;3ò¶W­õU Œ³d0aâ0ÔBs¼õ¿Üu¥9÷˜÷lÃ6oxãÈÖ«§ä×qGÕ:ï¬f9Y"Fv_GôrgÓeíÓFµú\ƒÁ„“]¥E4&²m^¾Êë:ö ÷¼~‚ÿüW[ÿÈ[Æ»3íÈI­Š¢à}ùο~xê=þüüʾî1ÊùðÚqþó{Û^ñæÕ…1龉‰ ŒAÐ.¯Äæ{íW»[ÉDc8®È-ÝPÞàsC}¿½f›h´ØŸnÕ+±lèԭ˴Љ6<=h—×’7v·4+ƒ©$f$§BâÆe+¼ѯc Ñ⬂—VíöJ´´GNúŒr0"{ó4v5+@™è(FX8BÐ#|Tôk˜qò¢Ñ\kJj—ç™.†ãsí׺‡z-=µ/É.ØYµÞ×Oøþ±ŸóçýÔ×}+]=wǵ!ñ•5>&ºk°Ùºô=BbivÁ¾º­Þ˜z̆úõ €ŽÐf?÷J¨ü=*ÀSõà©^îj‚ܨö^à^îªÞè•øyë8¢Ô\¤àìÁDy0Aø¼å<< ZÁ€DX{s¯Ð¿?ò3þüêºýežù \úÓ·/Câ°-1gEqÕz?GN{&[—¯ÙV¹Æ›Ãj1¢©9NzuAùÖåk½K…ƒwyñþóßïýŽ·(K4A‹Á-Ùîç™ ýŸþ„?¿¶þÙrÏš \z(!„ÂÁŸÊ>—¯ðC~á Ï_ n»GŸ)ý§Ã?âϯox®Ü3ÍÄ®Ç34®%æ¡ÕúIü—ó²DtŸUë½y0]j¾w‡>Œz(g§o¶Ö‹'œ‰ªôÍM/xóÀö"þµôtoYNÉUOy—_0]‚£ÅB%±ÂëÀ`ÚuèÆé;Ý“Z 1" æ_^¡?=û’ˆô­M¼N;Ò¡¦S¸1ã‹j‰ζT¬òfƒÚ£nô²¾³ù%o¤ÿûà?óçïl~Ñ+èhËy-qêU˜™·—ûtmdƒPú¼«f£¯[…ô}ôüù-/{ý%H<Òr®©ç6MW1Tm]¾z­§kcX<Ò|³BäÇsA9{j7{—`p0²C%BV(+5½®`ùÎêõÞçÕúÅEå}…´~mý³¾•÷ò§dí‘mSŪÍ~-ô?O¼C;—úª§¼c(F¨síWὨ™o(T”‘ÚÛ¡WW»[ÈJÀödÀ mð.†À…îêS}6d¥%¦`´Z]RcäK©ëæ}Ì&¢s!½ú ]õǘ¶öuN(ï³ L÷V”T{§{˜eÃDëê6wù=k<¸—¨ÕlÌPVJ:ì‰w•ž%̸Ú`JH€Á÷®«Xjº:N3GK·ª¯OO~š”æãh(´¼ï.fLº•`¼4½Š><65ŽÙ1²%E’P1ß]94ï1e§føî1a‚ v|fgB´ó•ˆÒÒ½»!Ð 8B¼9ßZ($NÏÍP&̆|Ç0ÞMÌØ+5%’ä»™;f¯…ª¯|oÐÒ+ä´gi=ôݶƒ‚Íð.m‚Ú+ôÝ1¡l´ùŸ 7¿¼yhÜÞáWÙ ¾{÷ö¶Nóm£ÓÆ}ȾÉ%PÊæ DuÝø‹8JáÒ|³ý!§Pœìˆ5O³>¦ìȬÍpÈz©ðêýb±#ª¯ÎÍq—Á|@ÖôìlÔ2³¡49$  Þ°·¨ÿÅLÞéÔìÌœ¨9K„må;œS§ç<ºÑ&LV~Ú/bEi3Í1LNO˧CÉ—ùXÁ·S†Ä¨ÒÀ”¤$ãi.;‚áÓÎ ʃœ† [AsOMD-³U1ìymô¢°#¨9Áèã!Uùd¯ÅfGð1öÏz4ƒwédG†»Ó’‹VE£qGC{Ìzt· õgbzrˆv¼D»¢¸ÞV fGÐJýcC^#Œ¹¨÷…A+õ z$F³Ü¬š‹öfdJHç¥eñc‚}€O,Ç~* ÝV.÷ Ýœ5$F•ïë½ÇEaGàä ŽÏ9à [ó¼ôl¯®³#P LZ¦\÷¨ŠJW†¹~± ;‚æqµªÍî`:Ǹw¸_9^îßâqx$.ÈŽô8{¥2¡Ï–f°Á„Î ›3œE-G¯³S2¼÷¸”ìæ$÷F¸V”PmÌЌǴ ;‚çrgஆ\SwÙh½#ý˜o¿…ÄŠÜbCâ‚ì2tØ] ]ºÁÂ> wÏ] Ó¡Ä'ì¥EaG02âîÔàîný‚Œ\¹ì•&‚ªW¡*¯Ìk—ŒÁ@Ü⬺ʄkòËÙÏD¿hº{‹&ò.a3½iQØ‘á‰Ñæ{í³nŸ6ªžx™×|³#¸ÇëwÛb>•s9i™Þ¾ ;ÒÒwÇ1&±„‚¢¸kÃJ4õÞ›œp ´1ß. ;‰h¯‰V‹˜B1`—nö¶yð”WWy=¢`v]ìZw+Sœð¸«óË‹ ²#W{ZúGcþ ¹èÚëÊë —uAvO®„BÖ—5pÏÅ ÕØÝlûÆöMFu™«KkY"ÔøbdzŠ.é]Ý fGPÈ…;×½ £­Ü4ÅP…¶’c(%è¡× fGPȹökŽÄXQPB¹³206û6í¹ÇU%5 ƒï²7ÆbEÁCÛ¼l•1½Z,väJws×`oìo-ŠõËV¤z$>jìHÇà]]·Å˜J/ÈŽÀ¢žk±¨’¸«f£¤i×+qýV–Ëv¨é”gV¨|r¹+·ä<9KbI…<Ó°í! 9Ò|cŸQTaFÞžÚMÆ=.ÈŽ@KaW‹(äÙ†í<€7øñõ“lœ9eæî©ÝlÌîdG`N¡¨ÆÅô¤”½u[ŒyÓ‚ì2à ­Š1멪 ^ ¼(ì¼8¨DL¢~Lh.˜Vi¡îQ[åÃÝí¯ßfx¿ ²#ã,r{v +-}¡oœ4rKóWï6Ðb±#_?A®‹\Æpðòê=¼/èà^?“&I™@EO´]²D9tÏ­Üéž…í=ÖzѸ‰¯¬}š™Â©™é¯Ó~‚Ëd–fbP6ö™dG`—x åâ  /®ÚÅë ø«Ë‡ú„ëH ƒãU»øOX›ß\=*î(A»VWƒÙLL>¸z”6qe¼㙆íÆÅÙ‘oœðvmÜT˜Å,%;‚‘å½ÆÏˆ‰¥¨µ¡|ÅÞºÍFQ‹ÂŽ`dyïʧ$Q®ð¡yG™`vS’_]>,)á_]»ÏX~Y©?|ó´q19’øÍMxDƒÄw.bÔƒ¦r_]·Ÿ%búÙÙßNz”p_ýV¯ŸÌŽ@"2ðê%7X]AÅ×Ö?cµ(ì$þä̱1Ô1au…Ë¿¾Á¤+…Áììçªuo·ûµ¶¬Nº¬˜¼`È3æ¡hsÌ;ä4çýÆ#ÖŒƒþ‡'ˆn¸ÇKÉŽ`>nljÜÞÀr¶àEËánÕ™Ûü=ÕcèŽÊõ¶%Ä{êö•~e—D&MNk°ÕvrÐÅNÞºL‹CΆâJ9+ÇÈxSA¼§¡þ ‡aŒáxAvdtjüjwë¬-ÑΆ—ç•ÈÖhè&üWÔËJ'V,3¦{ ²#xç~ý":߀× å’)¥`v…t õNÍÌp!Ô²êż sákAvd`|H/Ñ8-¡ÿ“NÌMÍ4¶t‹á·vmiº5ô{k©ÆFçb±#“ŠSì…®œBC"ÉÆŽû‚ìˆÞ‰žýÊù„Y­—¶yÙ‘Øî˜øò >b¤E`G,¿f}Ù‘¹X!.v$êÄù0$ÆÏŽ@œ*Äï ¨8a;³Žôµüò%:\êcBÎÐb°!»>³3*~†OQaÁ…Àl©P(~w÷‹%ê÷ð|rá)¥D’¹òÞu®¼ç5  vǦÍEv’‰†ý]v…Ä$ºo4¬Þà73³##“£^‡«ghcüìškhrÔ·ƒ£¹²’ÓŽÌŽƒYLŠÞ*0pûG™˜ž™tM¨XnJ$‰'{ãÃóéjNjñ=ûÇÄâF,A¼{íÁìHŸóJ¢7ab±V^YväîHÿ¬V£;SE …xçØ” –„·ýø{/'%ƒ£ô ÷ÍzHjº’¬|Ã$ÆÏŽ ‹uõÆ:š`G`ÆK³ ŽÌŽ@Ey—ÚUu½R`ì³#p=­jE¯2;…Ü£÷›½ý¶$3ß0‰ÁìÈÈä˜l(™ ‘§Ð]ª6•®ŸÒ¬BÃ)_2v=ñV?£pÄØá[iíïtöTLx¯*¿œ,ÆAÌu»z‰)î·LdGZúîLÏøwíš‚e,Q«Ÿ†3vjŸ°#œ…i¾×nWÛÓúx@d]ao¯u·ßRvL™V•˜`ÉØ‘.UÈ=ß"'/C£ÍyÔ6îrmi1\vmîõHôº²zÃOfGZõ{êr7‹Su~™±-ÌŽ éXÞÛÑ™ÓVÛ[¹š/¹ï;ÉJ±@…iìj2–zá«Kk)3ܼ³íW½Ø®¥½ÐÍ« ç0˜¹ÜyÓ»Aëd®3Öh‚Ù˜#«r/Ï-1Þ¸ fG0ä¾uyžG¯¤ßR…86Ðí„AÛº“m—&

Rì&ŒÎ»Ù®p`ž®Ûj\ fGN¶]ÆLÁø •»£re†ßr¨ÉÜá`‰ûëÍýï`vä“'åœW¦g¶³°%cGPÈçΈJ¢i‘yW»%LÙ7-[i숳#÷ ±åœÇÑS “—ݵ›è3´ÝW¢¥7Œ‘%cGà÷~põ¨ï<NãK«v“ëÈÛÞK¸u¹k³3˜›¿ñWÛŸà@²š5ݽ-Ý™ê +68[&‡šNÍ7éØ_¿µP/ÜÃïŠi²{´…DV³+1,‰}$˜úMãç–_‚ù}qµM`¼»,ÜT‘¢ð—Œ7§ƒÙLü%"‹R™Wì”—‚Ùx¡ï_92jÎC•‚'&D^Yó´áÙÆÏŽ@âÏ/t)¡ó˜ ~_ßømÀ…þ¼å‚åJv>Xic;*˜Ä·Ït¿¦eÿ²^ßô¼-±·ýº¶_‚Ä=Nצ´(ì<´“·.‹ źˆäBЃæsÈ_^½‡Fmx×?=û[ç²Ë8a"ðíÍ/?ŒŸ…ÿÅ…ƒ¾n ×˃Bœ¡ßÌ Kh8ùÁìH×`ï»—?å¢dqÈüêÚ}ôVBÎ#d‚• Ù4æoÿPMün}Ę/³#ŸÜ8uý®ÿà™úí‰ÌŽ\ëiûä†o×¶Pγn;°”ìˆÂAMö‚Zïë ûðdŽ›yûÂG\ˆ±ŠñúÆçŒ9Q0;‚‰’ƒU™ ™è#Áì ieÊJIç®t¼õ±6«¢qìÆüÏßžgŽfý宯º`v#{£Ñäh»¿a›}dQØØ%¹ð"Mì’±À²(ìFv{ õ¬ù— 1trfêï>û©÷KO÷þfï·iåÀ83-Áì.`v|À=_XJvƒõÝ‘þo}2Ì ±“£Ýª£|ÝŠa!jÇ„';peoôÞ²K™ðo]Ñr^Éü¼õüðĘåP¼Žÿ¡wd&+K81= OÛU!§ÌÔH²ÑÁdG0s´ƒŽ³TGæú²ZÉžÕ•ga1à##9ÝXÚZiê½Íà», ÿð’©Ìì|ëÃŽô÷L ÒÃâg…)€£ `GÐªÎ–Š‹Áÿ§D’ŒðEaGÐ/Œ·‰¸5à™…QG+¸Wíxo0œIr·|0;¢w¢g,É]ˆèÞ=¾Gqm˜º¿|‚Èô„‰%Á‚DI U~qþ²(ìˆæ$b‡ãXníG™¨C€8›^úÖä"2î‚¶´gœS6,§wÉýÚˆŽP‚?'FKŸ/ƒœ²´d u ;Õ}‡$FchؘÒÇÐð¦lB(,wÁQ+-1:15)«! OIJ–4˜ç{¤ HªeœÒQy¦m¬EbGÆ”ÁµÛ'Ár$: F<ìŠûÄŽ`<`W ·ŒÚâO^Ý¢³QdþøÙ4/g«3G‰r=ð¾ÈŸ vÚ5,Þ¨Às™¶Ÿ>õÊ„÷–Ã#ÅŽ «ö‹Hš£ ɦÈK˦'Ë úšE†lI ‡sR•—oibÆVéH(Œf”k:¸ CiؔϷ¦à§Äè[¬žáDÃ/‰Ÿ10“ˆ§ŒÇÊ‘–ð˜H…úFØ“@›CÉ ˆÚÍ•…{ÄÓï·ÅOô#° BQfþEsÑî Yoø¸ÃDP9K“Æ=ÆÏŽ Iy¦— Z5U«®Ýª¸e°`G U4;% Èæ]²Ì‡9˜Á­ñGÝä[Jp#º{†í}å¨V'8Ü<(@%Œ‘v¿jw nGb‚”ˆI&ItÞKVÑ€lfS"ɆÄ%cGÐ\lÀ“up#©ØE™ùÒÀ³#ÐnU4{~Zvßè · L ‚æwHA¨4_6ÚAö¸`v÷…¹%ìÐä{#,ºAº§' ªâA¢4ûËsK¥{ÂŽpŠŸÑÇ=ØóXxé¹÷Fïóä 9i‡ˆU4EäEb5CÊsëÿÒ°#°½Wº›¹¶hsää΂±lMI-Œ6†W~|¸X’UØ5ÔË¿‚u2biÄÏŽÀZ²9…DtüÎÁ»H-–ŸžSí>é#€™œ™¾ÔyÃrŒz߀ @jwϤHdmiô¾‚Ù<~o ßžˆ$Ñ•Å50&(Ü^LÑ"ËsŠúdžX"~bl*ÄÏŽÀÒ6vÅBà£ó:g4)’D [7{Ûù½1Ø%o½Àƒ5¤¤&&ñX_nªX%‡ïEaGŽ´œ“î*Ü5 T V9EÔØ‘K7…ÇóÕ|/ìÑLØ :ÈRHBD«D'æDŽ M›Ž;o° AË@Éõ[ƒvZ_VolÕ°#P‹7è3ænÕye‚—UþÒVw”ò%cG „ÌLÃÂd§¤ÃÑâowÕlÀO`f^ídã)Ã>Óä(ª'&2²…µ;r¨é…gê•âÔ¤Ù;v×l‚?‰^;ÆWWuÞc[ÇÉÐÆ%cGðo:Z§ü·ÜÒ«‚z\U\M]ûƒÆ#<6¡û'…#LZGÕ¶Ðî4á_³#è_ì' ­`á:OcÖêÒZÌì {¼ú#1œ(œÃèËköÂnw ÞåÍ'ÀŽ OŒþðô¯yEE˜Nf&§ýñ¶¯È¢‚Ù‘œ|—§-‚[Æ ùÚúgäºÐ’±#p$~~ñ ÿ‰Îw\§³>-=C1šøÙ‘ŽXúŒ´±|%ï7“DôGYT;293õÇÁs4Œqr“¯¿Øùš\š fGÐgyŠDÇÐÈYØUO­.©…Äï{{‘¸iÙJü¤WHü˧^‡DŒ)ìXââÎê Ç[/ÄêYZû’“c²#ðIþûçoóŸ˜ÜaBdKŒª™Ý_í~]Þcüìü™8úÿ¹«z#ìO¯³¤ gì¯÷|S?;‚;úɧkGák)‰Î8¨‚[ÿ»½ßƧ#ÍçŽ: .bD;*ˆÀ=µ›à¤áÃ;úÖÐÄ(q 0›hìn9øTB®.;‚¡óãë'iׯ †èFï-ò´ñ vr´[ÕE›[pJ³ ••p(¢“1ˆÃﶃ4„J²òǧ'F$7~OíFx¿¸5½4¡r%&„+óË0âèÐê˜ÈÐáb0ËpW¨¨Ì¦º* ó­(ª’Ãq0;µÄÀJMmO¢{çb @­ä¨@†7zÚ†§Æ(Ꙝ˜H ˜T‡ê‚r¹øÌŽôŽô÷Ž Ps%„ 3óÐýçôé<ÈÎK¦œØ< èaÈ!=àï©uû™ʨnÇ5« fGº‡úæ¢4—W/á£5Æáx;0 ¦rrp\vQl<©]`¹í—;×ñ³#Æ.-²1å}áqVN0;¢w¢£T›ÚÉ@þh=cÛýQfGð­û;wÔ¤JþÓð#NóEåUãìˆtw Ózµ§Õ‰í-ÈÈ…zÜîïêÖ[Ú…X[V?«ðˆØ»Ý«ù«aüìHso;ëJ^]Z ý¿ÔAJ«lÂzä˜xkÚó…Æáa(ÙAL8°#hÞ€J • ñ±I³l…ì˜ìœ„¦Þ˜&ì®Ù •gS`„ `GðÃãú£N+Á뀢ò;”L¡äø“µŽÖSÕTD–ÛlÛkô‘4Ä‚ÐXXZŒªòýuËA)€QAG`uµ`œwT¯‡Ä­ÙuDáè˜Pî8P<#X`ùþúžÚÍRb;¢¡Ûä¦$&Ñ=~æìûZ:xÔõ˜…DU žrüIš»g¶»ƒŽX»ª7ÀsÓË‹zÌZ¥Ù«„IŸA ò¬ ¨,$š‹E¨DƒxÁ÷QcG~+!Šî+ŠþÂ# ¬Ê®j×k;¢ƒŽ ’FÃKDE¿;yëwÌýõ[1OÿHÈuŸÌÛê™É鯛ôìì wm(áúòØOMU*á =²4ìÙÃB{÷ÕmAÃ#àÍZtŸm•kÔË— ‚J>¿r§ ¿¡ƒat#ôH;b±ì%ªýõÛ`=Ž6Ÿ»çìÒ‘4è,lL`!÷7l#<‚ËÙ^µNž"±dìÈ»—óš ŒŒ T‚ñ‘´Ää—Vïr\ ¯®Û©ñÁë')9Ç å1ÌŽüËùùó–åk`áÆ4ݵ7¹)ôtòô­XW¥½º¯w,mÎ!Ư£êPÛhÃíÇséé—‘uPÜ*Úã¡„>£ “xÖ¨&2Ví‚FwÌ—Šu±á9< ôPg¡\YN©´ì†$´*O9ŸiØçä\ûUVÚÂLäß~]j‰ßØø<ª_]:ÌoDì¨Z/Ï~ `G`¯¤qxiõnø*ŸÝ<«GmUzè^ñ‚Ù‘_^ü„GUØüÊÁåÏþØM~ÄÏŽ¼yö^(غ| ´Î$Ûj4Îw¶¼¤Y}õõ Ï›E;³­6B³#?9ó»¯Û–¯¯·„Ýi¸îߨøÜžOnœdsôÝ­/C—~uéP¿#¿’›îñ³#pÂ4Ç65ÿ|ç×,ý8x™ašªCmì©|$ 0Å¿¼#¾µéªúñ\Ó®mYi1|¼æÞOòæ™,Ç„¾²f/\zØsöL`ß^Yû4þ<îàªIáÈŸîøêÔÌôÛ>q–aÏ׊?ìÆ‹·Ï3¾}}ãó0ΗyD£#iÎØPˆJÐh;$þÓ‰_r9zäG§m¿ö…]Z =lëëc´õ×{¾%›"€]ÒÞ‘ª4ª„Ç193ýÇcÍûâªÝ²k°#Š9Ä‹ßÛö8?=û&QŒÐ#KÆŽ`ðâ×!àºÀ`b ùÉÙØî½±å%9ÅÏŽ¼wåSCá˜A÷0ÐH*=Tk `Gà©~*ü„ÿ°ÿáÕÿ ༆1k“è˜ì\Žïûÿùêº}0D‡›N³3¼Lç‡ý?|ó4µMr$ñßï}pê]~ñl_:’æ'ßå9Ú¦Š•p'0k{çÒ!º‚ŸÿoOG®°#pÚy*‡éÞ¿Ùõ Hü‡ÏßVó]—Vï’Á´âgG>¾qò¬ÓÑ0&þÙŽ¯BÖ:ô#6¡¯mxV®•ÅÏŽÄ‚Žè8Ö0˜ø·ŸüP_PbߨŠü¥ÿñ“𬠖°01O4õÞþ¥òˆýïO¿vÆ¢·>B¡lï>1†.;EUj¬w"¡K˜Üa6G³ÚëÄD“èw”ý·÷>aBa*1;nîk×¢CäsbDSN޽E‚-ÕçôŸž$.#l&f÷Çië]{mYM8 ¡6Ÿ·žçè ëÊêÐÙoö¶w@u®ìÔLé³#;nŒMOÐf+† Lä!‘NÃ!‰èŒ³ssʨ:Rê‹*3“Ó`‚P2Õ!'5£JÕ`vDCÆöA'˜»gå«%Ӳ½ÄÀŽÀ«:h½IŠ$¢Åæ¢s·û»pGõ¹CÀŽ@K¡o¥8S…fWïÖ*_E]†\¹Î?;‚0òr p†¡Ó£L~o}ÇÏŽè #SŒC¤ê÷ù'g&ýÊPDIa-ÄŽL:E…ôaI !Å@¾óñPàÏ_:;bàô­@ž°#±ô„ñù åÑisHÎÑ-YTv$Ö£tëQ ê¢ÓÃéâTŒ&QD ÕÁMŠ„ 0h>D\L‰$9ÖXCIH²Ã‡Ø¤ˆnu‘·£ºpª˜ä0tù–³Ñ®ê–¢0…Úðô/ª×ßñ§#QNÁ¢'¦§øa…¤ãÀŽ Y&fbu nd–¡–äæPüìÈŒ*!ÆvPX0´…’¬üDѪì~¥ƒÑí¤ÑV%Êç¾€ €tب + žii¶z.xR<7Ƴ(Î*4 ~N=ºMìßë–†%€ÁCä *r -­Ïò%fÌ pû|;D“X}°K‰ª6”{ºKÃŽÀtKM¨)(Çð«rWôŽ:1é fGšÄ‹b¸et(ysoì}5¨ÆbÉèЪ4& ¼¿‚ Èmþ`vÄÞØpÞøD¨½Ü¶¯Ðï8K–ÊîÐnĽ‘û¼É»$÷Éž°#œâgG®õ´rG+Îȧ2仕x@hùÈÖ¨@*rO³¿—†¹ÕßÅF%¶7‰ü°x¦çÄNpMÁ22Gr{˜fûügü숌¢_[X{2¥Â‡4qÇ\‰Â˜°#üUT´>u àVÅxën>v­-;-Ë"¿ƒ&D‘UqÍÕž»ð¨jpâÎß¹6)^¤“cMüìˆZ q<ü|™>ËYÇ'ž¬ ù¥ZMïEÂÆkÇìÈAZ@Ãi‘— -mTeÿ `GZûî°ÁÌVKT,b=a“CÎ{Úúâ$¯ÛDÂr]1~vDïÒÎÐÏB!ÚuÅEçÜŸ5aKœŸ™‹Rx[YIJ,J‚þ±Í÷Ȳ#üÕvÄ7=<;bÉ6ýýbGBN ’±Üš½dìÈdŒˆ±#ðظñÃ* ‹¡íOƒAW•±ï&ÆŽ8†€ÚäØ\ '$Hv„àHdGìˆÄD˜Aå¥Dyúx;¢0m…vžP"*¶¸ìȤú*Æè;‚jH‰r·#€™ñ%ügœìˆ‰;‚g!nÌHJ“§ü°#2ˆ³#”<úì~.O`¡-´Q7P‚¦“8‚/;‚”ŽHv¤HŸkýæß>;˜ˆ¼ˆ:H½]\v$ß ¶¦Ã˜ÇØta©9´ƒ‡zðoáBIvÚBA²#(<;%“Wú˜±ôtúwÄŽ_; Üá âDØüjÎÑ{‰(ÝÊ"ÅŽhL$ß¹èà ()”[õìàv  $Çíõ°#2 a"–(¡‹2؆/;b"KÃŽ ’âP ‹ö× †Y–SDæH™@ËãÁñVŠå°#è^ „R;¢ŠÐsÔÂdžÌ‘ l‹‹(ÁYºògG,7 ò„á?;¹­yØ”‰ü’¡0Ý;¢ON‰¹‘KÃŽHLÄ—ÁÈ^_´üœ¡ÊÈíaè†ÜMŒ“!L„ÿlp0‘3·ãdG0Üú&ÙŒÕù±uÉvD`": ˆ~µK²#–^ú¼Ðá`"QµöD‹¤è&ì2-:;"ñ™iìjÖ•MÀEŒ#¡#K v„€þ3€‘˜ˆ/;Â)°#—;›ø+fGÜ€HíÈR `G0T‘5¦jï­ÝlémÔ‹Bp}–ÇP_v$K¿Y勉ø%”Øtg5\Ú`1uUÉŽ ðÅUÇÅ1í—­ ‰‡šN‰‹ÃŽTå—Ñ»°’@ßdL„ÙKosr9¸ˆŸðà®0½!Ù¤g ²¸ìˆÂD´qìˆJÄvï£ÌŽ&b°#»ª7JÀŽ8_Ù›UdL$;ïSÙàt®æD1 äaÙ‘&"ÙùjõÒ°#øêº/¼ìˆ¥ß –ìHƒƒ‰Hvj/·ÓØ‘ë=­Lî¦:GÏHvÄÒ«ö¾˜ˆJ¾v„¾âiÕn X;²·nK×`/œQà° *<‰vêâaG¾¡7c väù•;aôxbÅìˆJlvDb"ËWÔk¥’áCæ¤eʇ6ízÞqÚi9ÅŽHL„Ù< Êù"¥vDuÓ`GP"¼7¶¼ä`"*a@§aH²#(‰YÅvÄÁDìDì4P÷÷¨s1ˆ°#ÆWÄŽX(ù±#ú«&Bì,ð{—?•»‡ûܘˆêh’I '¾±%¶ßÀŽt‹¯,}² Œ³ÁŽXµ %0;˜ÈyždÑÙù³#çPr/ÂnË­Px’„LÉ‹ËW–dHvä_?õš¥×^Þv{qÙõ•_$;Óñžˆ‹±ï3A2˜’)Ír"ì\}1¢Ùì†ÉŠýÛÝßôb"–›òW6NcG¬@@äÙÆDÞ¹ô ÏîŽaLD²#Iú¸οdì¾âMfGþùä;Ã㣱‹‰Ÿ‘_ù²#‰ÀŽHL„™€ß^;ÆË(ÀŽx1Ë(yKc"ì]”ìþ¤9_|hv>¹I’Y–[$‘ÅeGà»ðæ™x"¶èìÈßú!/2;òãÓ”ØìÈò¼#8—ùî–—QIfG–å–àÖ,=·=¡g[_";‚‘—¡ _vdMImafždG^ׇ7Á»;¢Câ1;‚ï‡ÃéfGàSµõu8çѨÓ-%;²Í™ÚHv¤:Yb8¢ã€ºØÌUTÑøØŽ·ª§BöUÌ_Ʀ&”Åv³#˜J·¨ÊÛ±¡<«°#Ó“zæèbG,íuÇÉŽðš¶Z*ךùÐìHR$© =Çr³#–{“eqÙ‘HB˜æ›¸ §[…h/’RüìJ¶O#²Ój_˜¶ðâgG¢¼ø{ÀŽDíòÿÐÓvÄç«GŸ™žŽû ìHþ¢ìLµÒ"²#¨*×öÁÙ‘)ýÿùe±#³ÊR‹`$ÆŽû®Ò—ÅŽXÚ™ˆ]|`vD~õر#ðfXsÁŸT™‡`GòÒ³åÃz¼Ø¨„¥÷Gù'´ƒˆby×z`v]†W„¿DvÄ DüjiØKo\ù²#ìõZ_„éR_ÙðÙL¨ã|éì,C¿°9¿kv„v}¼ìˆDzŒ‹”Ø|ÕN_=0;g„ ÂŽ<^ìHmÁ2i‡—ž©ÑÅC°# ';@~õ»fG¼€Èƒ°#:ÄHµåÇŽœ[¶,;B«K¿gìˆþJY¶¥aG`î*]€È±#ê«|õ•ÁŽTæ—‡þü®ÙdÆÅ/ÊŽàW´´÷å²#–ÞË”/vùe±ÈŽÀ¶ÐW;bi#Ï?ù]³#pФó%²#ES?;âDˆQ_éÝ /;"÷óYv„b9xÙŒJìã-;²¯~+F¥/ÊŽì¯ßZ¨'È;bÙï˜Úé ±#WÜ€ÈïŽY[ZGÎç"²#(GS %;‚?8ù®¼¸ ;‚ô'ypv„¾ò²#PoLÉqv’¯n°#ôC¾òh²#›+VÒ+ì‹ÈŽtöÊ 2ÂŽ X\LÙ¤¿€È—ËŽ"‹ËŽðW‹ÈŽ`êtÂÁ²œÁWrÎõ ìÈΪõä´<;‚aNòàìˆüêÙ<‹äHÒC°#–>ÛˆËùRØø´ÞõìÈþ†mp¼ìHÓÝ[M½·¿(;b©ÕKÆŽhëò²##“cºòÖbGœ•Æ%bGR"Éòí‘Ç‹±<;}ñ²#Ó“z—v‰Ø:(ƒòx±#–÷ÓjzÂŽø|õè³#wdÖ9žæAÙ‘¤p„êü$îÈ“¸#ôù±cGPOVËdGÐ\t_nÜ>Ȇҗwd|jBé€sñAØèIvJßΗȎ@K»DôˆgGð+Öðß5;BgÖ,bÜïñ4ÖãwDOë8WÜu< 5à³#Ñ'qG‰;òXÇ©)X&ÉãwDd“CâgG.w5Ù.Á—ÊŽ8Ùü±#0ƒ¼ëiýîÙ´I¾^¢gÜ‘5euGšÏñOžÄ¡Ï¿—qGè þóÙ‘M«h„úrãŽlp²¡ôxÅQÚ$ötÉÒÇÓXmÜ4&§^vÙØ[vJ£Çžð²#»j6Ò¨½ˆqG|/R `GÔñ40˜_„Aw ½/=îOÃ~Yìˆqf̓°#ú ›çcÅ>0;òú†ç0`= qG>VÇÓØN˲#{j7“Cþ¥Ç¹âOóàìf ûêT×^Dv}·À­Ž;‚‹oÿˆÊy¼Ø‘?̸#ϯØI'T.";•`×ñww.åWõX_nÜ‘ºÂe’xxÙ‘ÿzäg¼\ÿ€ìÈ_ì| £çcw?§¥¿EŒ;‚*ñ…ØÔ!’¾ÚÓ²dìÈŠ¢ªáÉ1/;‚ùË­û]_”™žAS§¸#¸I©KÀŽ,ú™5“3S³OâŽÐ·OâŽ3;B@IÔ¾£ä”Hìa=RìȘ¡}”ÉTÆE‹ÊÌ:jé{f òà‰Kv¤0= *!Öƒ³#wGúÙN2&â ”PZ\v…§èó\´Ä;bé%cþI)Ÿð79fwÌ„pqf^ÿØ3èÂäTIvw¿‡÷ó˜ÁcÂóè6‘Ï=NvÄÒ³DþLìò˧€;’½)€Á¯”1ÔŸ™¹3ÐÍ&m(ÃÇ= ;é4çÇ“r¶Bmv¤G„a·Mìߣ ås`G¼˜ˆåw nŸ»¶/;Rœ•/·ù—†évc"–}Í}qñaب.:òÕé$R¡vOˆtÞ_–Êïìï^X;¢€Áà"®8K–þìTÑø„¡?;‚I)û¾ìHU~GùÈV–TÃcàh틵ɆòظµTìÈ­þ.6ò¾ìžTúœûxš¼ôl¸(Ä=ÖUfŠÆÉŽXzí˜?;B@IœìŒu„+]ÍŽùŠÂªÈ•Óv­-;-ËJvD%5W{Zlk,Ø‘ów®±Ÿ°èìˆbD%fG DÙ(!òKµ$LÄ`Gäf­ÈŽ\¸s»ª/;‚v“[àìš”‡NfGð¬y˜ËOϦÕd;ÿüìÈàø0uUÉŽ`¨’š†‹èŒÌù²#AÐé|§ñJì6™ŸÉRÖXW ?¡Óâ%;BÁHdHöµ¥uð[0DÊçþpìºüª’jËÍŽÀr¢/È]ObG0’Êך¡ä¸">:ì\²#ðäÊéâ²# ©Ùd¹Ù”,YŒG™!LÄ`G^tï>°#];®Ý*¥:pTÈW‘ìȽµÃDôî |ŒŽž2õ°ìÈz‘ìÈN(¡´4ìˆ 1"±—ÁÜðù•;$;£DÛ·’Yá%”Ø%{3Uw鯭Ær³#:‰ÄD TD¹}xí»Ç_ ;鿹z”FC¹Á޼¾ñyÆD,=M ®zæö8ÖdG`X^1Ï­ØIïQHvä››^˜HŒAg"¦†ã]5ß»òX…»H‡wÁH,ÅÕÅ mý³P{ø'íŽf³#°fŒwû²#0¼´?J)€Q˜HÓIƒÁÐÆi$ùÆÆçO´]bØNc"Ê`JvD#‰Ñì|ƒÏnÆ1±#P¢Š‚÷ûU­™”ØKoVñgbG(?³#0r"';ǘvÂ(ù²#¯mx¶ý~[o¶‘i²#í÷c?Ätf[åZŒ¶_€B]qeÄñü«5M•`Rw÷tÝd8)~¸½r-¬ÍY…¡h»UNÈ*aÒãgGЗ9Ƹ¥·`!·^b‡¾Dƒ )vÄÒ›‚Γ¢k@ÎݹÊýVeWµk5€AKŠpùÐUí“·.qÇÜ_¿SæÄÆáª’è~Èn½t(%°#gn7ò1 ¢#c$•£ü•OÉÖÒ°#°½oÄ6Å÷ÕmÄ#`»«‚.¥b÷³Å}õ[áѾ@ÒѼr `G`¯SÈÝ¥ÑõàGIR¤"·CÒ$°êȆªÊXA»k6Áíä?—†±ÔÞÆa~çg}YÜEŠ8¢Ó“_Z½GÑ$†CWMKJ=xý8­Dµ.­«ö숥߿çÜõå+à<Þz¾sÀžtÀsxaåNŒ­Ÿ·Ä‚¼¼fÚD7à‡E•G[Îó( ãç‚  $E ´Ñ$M²‘~Ø|žQN"EÚú:Ø|áî^ÔÌ¿¹ú9³)P‰*V°#Ó³Ó Mpôx{Õ:Ì#ÍgyøÆÔcoífhÆ/º‚J¾¸Zoi_:¬GýxGÕz s°#˜§¼séÿùÒêÝðU>»yVÚª(x {ÅSfGÞo<3€ùËvV¯‡*ÂP;‚NýmýN6§8ÙKï+³K%„r­»•m5i(mÿØÐ{—?埼²öéŒäTa®êÊ’šmb?>€AúÉ™Ø}ů ÀD@HüÆÆˆ&asôêº}Ñ~uéЈ3+„n\{Ñ9~vN‹ŒæõÍM/@íyéî·W®ƒƒá¥IP Œó­MPÕï‹Ñ$;ªÖ®)­ƒý¿ÝoÿöÍ0éq²#˜Èÿ¯“¿²Š^#>{Ë‘ˆyÆ\I“d8¡b~ræ}zQe´·ÊÑ!€žûI,¢@ô+k÷!ƒ—‘‘HÐ,ßÜøÂäì” Ep`å.8ºoÿPPJÉáÚÁ&à‡¼·IÁ_ì|M6E;Õ=­¸vUéLHÜô"|•·„úªÊsVØŒ#?;û[^ÜøÖæ3“Óyñcö9ÑYˆM¡´dì”ðªãÃFÅ@ó“³°Ý{cËKr<ŠŸyïʧŒÃ1ƒîÁ¾½}>ýùίÉeðv3G¦Ž’'ûÃÓ¿f6Ú+'ì¦÷Y M8°ê)Ì`Æ%·Óq®ýêá›§©mPÉïmû >ücoóNuMI-ž5OµTx’õû¡ü Vâçÿç³"›+€ÁÙÁ€Ä?Ùþ*ªúŸ¿m¤`‚ýò…¨øÙ”ðyëyGbÆŸíøêàøÈÿ<ñ›P¨„Ì?;g_ )ÊÈûîÖ—!ñŸŽÿÒrnòÏu”‘ÿøÉxÖk‰.v¤ùÜÑ;|#\Ž·ç[˜Ñ¼ í¥ýÚPèO··ðƒSïOŒé !¨ÐN¡BKÆŽ@÷Ô"•Þ‰Ä8¾§v3\}z²´\ON´7›áVÁ‘ƒÆvÙ¢CD0ã2¥ '>§áx&6=ŠM ô¾ƒ*¬83#Tç`/ffGöé ¦ UB«Jª1`þ®ì’ÎEsa¾‹`vD½Ö29J›­˜(ÁCëêkWcœ-Ì4ë°#ô&RKß[èbsR3¤‡ÌŽ´ÜkŸ˜™9 ëݯ–Lû¨¨„„ß}Ùx àÐzC/jÎÌÎvê)ô“â̹WÀލ7]‡û™óNßÔƒ£º ×Tš¸øÙHvZÞr^ðÆÀjìåqþøÙ‘Ù¹YÝm‰hÚPvviCz{7¶`ÀŽXv\› ë*Ôyâô c+ó‘eGøÛ'ìˆozvÄõ_*ÅÓ’;béÈŽ–Dé¦8ü†¥,{XŠŽŸA‚ùP"œ¦ÂÍÉv#šD“"1à#Aa\±”ó%&D|c¤/G}%&«ð!ú°›™i¾q´RT܃[HÒ7;m[Øã“…»aÔ›åÙ@)IɲUØ]ù)ÙæÈ ¶ÿš!³„{âgG&f&Ù´…¢ÊfÉF†Å7ɰ#¸5YŸ°Š;+*9’dl“ÇÏŽà¾$mušvÇ¡1š7€Á“•õ ëãodpO•Gˆ!As‚£‚æL3 å§e‡ô©O‚Q²f4:F¢¹hgKv3n_š­ ÏÃxŽìùü'ºŒdÂÐnÆÍÆÏŽàÛ>ñ­ÕSH…мhG?!_…IÄã‡cÇ}yf•‹`Û›DyÛcê°›!þ-~hÏÍôß™ŠípiNüìlÕÔHò˜êwv=³œð!œØ:ì†U4I«+r«rì}ËpR‚Šb‘GbÁý¥È@ÎÌ3ªµÆ_zÞ@2ó±#tkòt0 a"fRBEn1þ˜žì4 Gäa¬*=1U i-;¢šk¸8vÀV%HûYî=C)˜Á·wbzM¤È€RP ºGÌŽØÔhÔ:If#š„ÿ fG`ŽÔÕ©~(M1zmKàñùˆl2.Ñ$Râv„Rüìˆ"EzB·ãÉþ¬ÊWí†>+,”0:9ÎjV‘[’çÖÿ¥aG`i%)B‹{Ñ$°ÀêèYÁy¤'§IíÊOÏ6t#~v¤ot Me1,ü“²ìÂ2w™ìîñbgÓ¬sd4y¾¡cÍ’" Õ dG)¢Æ& C¢?ª}/ Oe?¾¨-qbfZbˆòk1ØHäÍ*ûc£™)´Ö#I]“ ˜B 3\=.€1H‘¼ôløu|D“È¢ØK¯ÈK¤ÆŠwq0–m­\#½ÖvÄÒºw‚«ÑS:œëËê1˜Îè7ŸX"QGc!k[Õ:ü ïEFjÁ…_[!Xì$žh»È¡Ñ[1öÅ"ðE’vT«µKôèkâDŒœÔ éIV©Ø$±4+AáÇZ.°¸y.‰‰É´1‰ò”” %MbéÕj¾IP󩘈ªåÂ÷Š[œìˆ¥7–xLWl½b²c6gwí&cï‘bGnö¶; Q![úÒkËê˳].J;¢I‘ˤ¦¢èoz›ÐÒG§I׸£r,Ó dGúFOSƒö‹3øà^!²–†A:u;FŠ`šŸ–#ñë]5ðÌ¡^?Î3)˜8¸^ ÃÓ{aåNYf;b©-s}:\PTKLKL‘18¡fäj:Åa$lj–›D–¹dìˆ$E,}$ ¶·¥bÚ¯Ÿ`³¦î1)•ÿÄÌýåÕ{äl:˜iìn–Þ E:aß]‰Lâ¯UL‘XüN)11þ£5Oëãu\¤ˆ]”“Põ8ÀXH¤¨—÷×o#òÝËŸ2)Â3S®ÀWô>\x;bé?mF/ÌÌëóg¶C"*‡±%â³ãÙF1ÜP ‹˜ÄùÙ‹w˜œÚbÜqqu£°®EÂk fG`r¥Y´ª@ìȺ²úõî®?;3(Ï©È)‘Ódˆ#‰¿½zŒÝcÜ#ÆÇûÂ|}]=“ÈŽÀõŠ…Ä‹*׺]Lvv×l¢—­uéP¿3ÀÑÅø(ÿ$š„?;‚ôÖ¹yÐL´%²Äom:I4Høê°½ìŸ×.§Pj'Ú.IúÙ¤%|nÅÎÊ<—';bépk˜°‡W/'û¯¬Ù 'ó}îD1pà ß2f ßÝò²,3€±t,"g,ˆªw²3räyÁè³eZâNÿšÛ38 ü'Å&±tðNmL¢,Kµeùj)Ä dGàüÿìü‡C漂?)ì§vÄÒx®§Ÿ™œ.#õ~oÛWäDfÉØÜã?Ÿ|‡ÿ„¯Ò;z_Ý£n=ä4šøÙ‘Ž.¨ Gîs«bºdŒÚìÒ÷ÿ‚çhh@ÌÈxà#šD.Ͱ#–v9J–¥—nä ™qóˆï{{©-Æ \á0˜îQD™;÷{$éhµ©b¥Á…°#(ÿ¿þ6Ï_ qSWKéµû²¨øÙþߎ¾%$æ éÉ `ù³_•EÅÏŽ`Öö÷GnU"Ä«•QÔNj“¤ˆ¥×ëdˆDØ%Šï¥ã¦ô;‚Ùœ4¨4m¥$&ý«­¯ÈÕã%cG0ä}|ý$ízâøpKtäõ vr´[Õjox‡BpäúF|!„îF¡ ?ºv||f’.ÃSMŒ„m8Æ Á‘Û_¿+F“S·/ó–|nz6½ IØ -Í]ínî²a T]Ï GBN>#Üf0;241‚r$f¦¦£V„Á¶õuö P¶pB|B8(g]¡k,˜Avöò^`zr*y›TT~FN1e²#sѹÛýÝQk޾‡‰žÕ{:wr8ÑXÚ `G,í®;cSH¯Û‡•‹²ÛhÎ?;béí³Y±?el­ÇÄώз¼¢}aÞ#¶B´/“ÈŽÌ8Gg°æË0h=cÛý‘bG,1¿|ÂŽÄÒvÄUGøõ²åe. ;b‡ñ{tÄ.Ä=â“‚ŽÐgz„knQçw,z5¿Ea$ôjƇWíDAG¨ðIŠÀ'm¼Ù•¡G<•w±bGÐæã^‰ú¯p‚™yQØWè·X#舵;b¹CÈÒ‘µŒn?;b¹CÈ„”é‘ÀŽXîÐ#2EufCÿ5vÄ=b‰‡ÉÇÓXzö5áw–^Õ%2 JoiÎeº,®žw+=€±t›K^D¦‚ôܰ{ŒŒŸ±ô³ŸÄ(”¡(#?A«„z$–IOcéæ›‘"T1‹…1ÍDTÕ⬂·ÆÏŽXîÐ#Îʃ ÞÁk4Ì~;béÐ#Cæ=FÌù)îÌÁìˆzD%cèqè¯a-D·• fGŒÐ#2ññ4–^Y›Ê1\iyN‰a–ŒÎ`Þ8'Gd'¡4#xL0;b¹B¸(CuA9©$ÊÐ#n‰)¹.‰ÁìˆE¡G¦}Œ dÕ.c‰úÅ'Ì:b=aGDŠŸ±dèOëSÐKûK×zZDDºXvX`ï.æÒ°#–;ôˆ‘(è}n8ˆ¼KŒ,kKë w4~vD¢psPˆj‰ëËê ‰숥LÍÝNîÉXYlffGà\r2a”n8…ô¨·Ÿý&9|è/§øÙ¤æÞv9–‰]­§±´›w¶ýªD9yƒŽXìˆå=b$#舵;‚rbUÚ¼<·d¹{#$˜Á=ž¾uyÚïùxË8È&êúOƒs<åà Þ¢àEo®X-_9²ÙK›ñ[‡’‰‚ŽÐçóâ ©8¸³zƒá½°#–:V¦CX.ÛDAGè3ž2‡‚3î‘«¸²qå-Ír±‰A! Þk±=vdfvæðÍ3òNÞ #V ;‚t²írÿØ€ñ*wýVšÁ8ÔtšçJ2yƒŽXìˆå»ön¯¢vRÜ™—ˆ1BȦ¥ #ôYdÓæ-<ê :b-ÄŽØ¡GüÖ&(è}–¡GŒd±–QÍ5æwŽ÷¿Ð#2­t±bG ñýÆÏ˜Ô±øœ #t–ðtìP'W‚¸ÕÎ+­2ôˆ‘è}\’øÞ•OyÂ.ªê=ã`2ôˆ‘Œ #ÖBìËw/ö-ªÐ9žÆÒÛÕ’æ)j±bGŒÐ#²¨j;D^ fG,½]Í>v¬ +š˜ymóÆò}üìˆå=BÂ(Qл…ƒsÿÎÎ+mlG³# ܹ|ØŽ+éÙ)è}8ˆ™Œ #Ö"±#ð—Ž4ŸŠu>žÆrdc$ :béÅ™Ÿžý­|]‡“7舵ìüù7Ï|à»ËÇÓX®ƒl̼O»ƒŽX ±#"ôˆk%Á²bÇÓXîƒlŒ„Á‘gÓ?:ýk5AðÜ@R$ñ·¾bl€°#–zÄß|AG¬…Ø‘N7"|ÂgÝv`ÉØ¤®÷™æèÖ3‚ŽX‹ÁŽXîÐ#Æ*†tÄZˆ‘¡GŒd±bG†&FdŒ™–‰ÌÝÍó :BŸeè™’#‰¹ëucÆÀŽXÚi—Lžm_Z½[†…°ƒ±Ü¡GX$É5‚ŽX‹ÁŽX2ôˆgÍ÷ }< ýñwŸýÔX“§„9ïßìý6}Ö¡G~CÛô!• @  ;Ýú³dìˆE`hGˆ·>­üW:9ï7a¦Äâú°{F“U葎ëv)"þ­+ZÎ+™§n]î·y!NÿoOÍ&ZÆ|ЉQÊ{;v™9©Y;ÌŽXºw8‹#Ug‡Ãœ•z¤«‰÷dcRÕÒVº±´ÌŽXzjÉë粨„P˜—L9°#–}bûoñ3õbù­¢³#¨’ƒ:-á|LKLÎö¼°?;Íq¯¡qkx_ù^vD‡qí ñ¶L$!bl̳#–ŽP`IºÂù¤ÞCN0÷ø#vÄ—=øƒM‹ÀŽÌsÄ2<&ìˆÎ@叿!8b-;‚4ãSW8Ñ;âòÊ´xûœSĉ&Âw'û!ÝuW¹A;3;ë]« kp$$~8-Þ>§Ò·é>vgnÊXEåU(Ù¶ú<-óqƒ^£ÌŽXŽ3ÎK¢3º 5[vDWiFƒº.™aýFWb0;Û= n¶j(5)Å‹†, ;‰˜ÿšƒæ‚söØß`v$ª0šqCÁPùÏÿ£ÆŽXjs\®Ç‘\Ô\R;¸ÇX9N·Iir¿Z:01"#Y|%5Ãû˜‚Ù< Å,Ï™³SÌø%Ö"±#ÐÒûãÞ{TÊ“‰u·ñ©‰AºG‘ ùé9lL`Ùðh<«œÑÌät¹±§º M¹%&X¡¼ôlï=. ;‰÷FìÍ6‡AµÑþ‰›ÌŽ ïôJKBº“›–…Û4Š fG,Ý/d/£¢ «ºUXbïpÿ„Ç®¤çxŸx0;bÙ>´¹‹†ròÓ³¥ÄHgé¡6y¼÷¸d숥—_Q±977IGù¶bAv*Ñ5tÏ>uÕɇ{,ÎÊ—­ }¾;|ß0˜H1ZäÅÙÈê¼gðv(ÓZi`çï÷ƒ2`:öH|ÂŽPZv¶·­¿CÕÜ5²'@]¥Vc‡FøHTj¹%^­^2vÄÒì‚;@ûK{ˆár ŸÃw‰{„Vx½…EaG ¥mýãîA“½º‚ŠLGÌŽÀ€ß¾ßÍg ð ”e–{lE0;b黆]“_Î>-$¶ôÝÁ8ë¨:ˆoûÇÏŽÀ…kîmw Zb~©DÇ ¥Wºš |viEq•·³#x­»ÕX¶C Tç—{{n0;‚‹$PòPNMÁ2à fG,½Q Õšqß#înui­ô0¡Ïöéb‡ í_#Œ‰Wºoòg”P4W¾ûí%k!vÄÒÛÆ=C&‚ û,{.:εž6§ûDYâÚ²zoG fGÐMwo;»Y1ÛTåDa‰°á§‰ëÊê¥ùêr"”È¢rR³Ö—7hQØK«„4$v ªhÌ)5v„2œk¿f8ä°'ëJë½æ+˜ËqòÖ%;M¥pBduIµÜ€éî»ØÑ䕸¥b•wÞÌŽÀΟ¹Ý8ä–ˆ6ßPÞà"—Œ±´}¥»Ù`s[åšDñ¾ <iL(Á³2Y ±#$ñrg“1é€ ½½j”…—¯þS‚×áÕ±%cG,åk»hL¬àË=Uµ^Î)T„ñv5% UëËWîq0;B޵žw!þQŽàIëÔØÕÜè#±lã²²U¶œ3<| C'M+lø©[—•Jˆ%EÈÚ^µVJ¢\èýõÛäørUœeÃùàïªÙhÞc ;b)Û;ôIÓI5j‹‘ŸiØ.ùyq– 'HÜS»É¸(숖xí¼ŽÖ&×…ë —ï¨\Ç{0ð´Þ8aÔGÎF1¼vB/9ƺާk·ǵì&/‡›Îï AFÛL1=×ÊìZuX[Z·Óc̃ÙKÏ#޵\  ª\r¾¸r—l®Ï[Ï{;&[–Çæ€>i:¥Þ× …¼¸jw™gzÌŽLBb˹ë7:ã÷ާª6ìª1;Ú¢°#øñ“±µÇ„ù¢!‹ÂŽª­}÷ æ³+¶ËŽvw¸ÿ_ÎdÌCñh¾±ñy9…µ9tã”ÁŽÀ=;°ê)c©v)Ù˜S¸p½Ãý’“ƒ¥“9Þz€dG0ß\±ZF¿ÆÓÑ«^.vdYN± '6>= EÅlB²#‰ ‘5eµ2ì($^ën™™›“ìHFJÚš’:㕉Ù {I*JuZ5%Päo‹i†fFWlN‹#‰f¶YÈhNŸ}v²ùJœqL Ák•H"Ì®ª–¾GmÝ|,dÉ}»ùð}òŽ#Q„K1ŠÒXTB­ð¬½–We››Ó=ã]yØh]Ö}Ÿ£\ø6ŽãáD0ŠåôJß*H¤³~ ®D/¥Ì#Q®rÇñp"ÔfV©DHÅz‰$ùfðÇ{p²}[ÕÒ[éRâ|| Ç­…,ßGKo®Ì8¬@²b3}$¢å'¦'©EÂáäHr²ßs„—6=‹ÛœQ‘xÐ\¨¾:F$ „FT ü$/KDI.÷Ì·ÑN1] ðQ±´D²ÇÒhfÖŽ”š”컯NË­ê] „ÊÃQ#‰è>é~EQàhüòÀU26_)¡IÇT‹Íhh,‚Zy7‘N€B¸#™É龿WÆg†g6N$yˆB¿õYH™ÅÔqzf:W)¬È_ó+ážÜ´L/\bÙMð=f¦¤ûš&Ef&yÕ·¹Ð}ð€¦f ˜As¥øvÛ!g¥¡Î°6YóH”¡qQŽoQx@Ó*$,lEXõºªZâ4™‘'I? _+œ'ä™ÉiÞ JêtIgàËOÏõíh:n­«Iá$ãEOJhsôrBQHzrš×õ·´«}/õÚ'¢µ™›œžRg„%&æ¤fyLG.™˜žÆ‡dÅ–¥úv[|+5ǘ±S¢£¾ }  ¥á½Jˆ¢P1(ò#OZRjžŸÄ %1¶…éÝÇ¥48>̽}Ö8rˆC!QEâøL(C·èÝU¥$&+'ÍgnF©MìÜ—dxÁP’hUÖÏÓTߢº{Ç`â7¢, øJ¼7zdb|tj,E3Ž(ÊkW1Þõ ÷Á¢z)ú(1Ce$>SÙ @¦F9Î¶Ž cb”:b‘rÔ;è¾–\?ëBCô‰c>¼š¥MrŽMOÐ4µ(#Ï·kßèáùj~zN¾ŸDrç~2eig¯otp`l™1×MMJAãûú ΙM*¡ùÚ¥ûãÃèÚ( 3Od(HÏñµ9ÈÔ „A/ìÊOMtßÿ¨!zYnjæ|{{°ä°à ![iVoÅ$¤…r|‡!K¿¾ÃŸ+óÊ|­@Å TÈP’]àÍO-?:…Ácßæ¥gfäùºLWºšÙVçûKDœ“ ƒƒqª(3Ï7[k_;¢È㻢跑>dC QHQf¾¯æô ÷³ùB6/s`i×9pwdj ¥¡VPBã”Jƒ `jd$¥ægäx‰K/&B%F'ÇÒÕȘZž]ìkåÐgõ“j³âÌ|/$d)•躉8KÉ©é¹ÞÑ ·Kˆœpª3ó*§¨ÑÛ÷»G&F§çf3“Ò 3óü³MŒÊ½ï%I˜Á¨úeé7óøóÊâj_+1,âùf–^»y¯9áÀÔCç¡„?Gôd›XRí»l×ÖßyW…7Šo!±<§Ø› ¼­¯sHITÙ0dÏ7ÔJm§gë…ú,F+* õ‡ðüÂ.ñ‚鲜_—IE®ÆÄ …P’‡jAèšRâE!ÛàÄèØäDvjL„¯@RÙÆGà˜!Õ·k#Ñ2ÖúID!èÚCz•í€ëK¡¨4ª‡©æÈcjédëºÝo“»\æó¾Ž8PHT´Õà[Æâ‹‚j¥ó,Œ¿÷jwËÀÄ2cL/LÏ¡ð:«èû·û;á`ÆŠl_|{‡<Æ ÙŒ7PY"Tb@{páÊ²ŠªòË|%BWÔëÓȆ™àÍ^ëné×!T1sAŸõíhÈpÚ1Ñh±†Ä 7à ÝÊMÏÄÄdUiW"¬ÄMEܪÉonZ6:£/jsÜTl{¥ÿîøÉ¶K죜:Ï‹ŽÄÛ}êí)xãõ…Ë}=L¸^0¨?ÜuÊæõÛ1#|ÊV™WZ_Xéë“‚”šzoßï €‘ýJçMòšÔQ•ùe¾SÂwo!*ƒ¢0ù¾x€<‚ÌöˆÆ¿p‡`‘J³ ×éC(ŒK‚ÊÃIKÖѽækjfN:JS‡½¦çÀOðm.ægwÍFß¾DkGßÈý$LÆÓsÐ}Í×µž¶ëŽŸ°B‘‚UÞ<¨öÅŽë¸AÔƒ Lœ¯;lG)øÚ<[ÚÈsO#2Qãp^6ñç›hÍÏ&^è¸~G¹¾÷“Éð7VWûfûìæYä¡ÏçE=(½}á#!q‹ï4çük°öí÷{ õ<Eùfûôæ™Þ{ÍduI­¯D ÙÍ÷î`”™œ™B!«Kj| †ªÆ.›bD¶}õ[½y0¦Ÿk¿†¢ s%”³©ÂgP€DôGäÁTÙ`¼QäÑA"UQ…™¹°ö¾ï1j:ÅëBÏ4l3Ž¥Ûu¥ë&Š‚bDXSRëë#Ïe‡ùÀœý'8–‘Þ<û~¦~»ï ¶ E¡b¸Gµ¶¬ÎWâåΘD˜ˆù^Ýùñ™÷ùós ;|%^îljº{“>̹}Ö› ­zêÖLT ßÂŒo«\ã]=Æ·gï\íîGGÃTÈ÷-&ä*œ+¤b‰åî®ÙäÍcé7+88_Cq•÷53J¿¹z”6ÐCVhkåß1v©WÍjûsÒ²árTû99äÈ jGßÂâ6½N½P4<gu6;%cYn±/ñy«mÕ{®fÉ郼KLÓ“í=˜öêYa:L“¯÷2#9Ô:ü|Ï»O+9I©é‰)ÅYÞµ\Ì_úôòÅÄÌ$-Cùªýøô$:†Võ]Ü››CC ë¥{Z2Eïö]·§m!üÿì½÷—Ç‘&Z·½÷Ýh 4¼÷½J"契Vcµ3ófÞÙ=ïÌÙÿáýðÎyûÞì›YÍí¬f4#ïH‰EO‚„áÑpÝ@{ï}ß®÷eFUܨ¬ê¨{ÙF”È{«óf¤‰ŒˆÌø*²¢ ,ð„M¢»ÉÒU0QåžÂ-äSìîOBèúB…®¶m ÉÌ ÜU-,.ÈKZ—:™T§%vœ¯Î¢ƒdñÅøÌÂ\\Å9U¸ L=\ sBU_`ØÑÒk#é™i™Fn®JGÇt”6âÂÅœ[itØ>-3$ö­Ö*‚®ÖÅäËBK…Ñz,§—K¥™°Åûܱ%ÒLPmáØ®-‘1%Žøè#cG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"úwCv$¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Šè÷—"ìHDEQDEQDEQDEQDEQDEQDEQDEÑï/EØ‘ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ß_а#EQDEQDEQDEQDEQDEQDEQDEQD¿¿aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ~é#cGlñßþYª˜¨6 .f;ålªgÉbº ×ȶùkZZZ`U‹T•MM¥q´5CjLqŒ6lÑ)äK[¢X|1¾èŽYz,--Ð0T³ˆÖkŽTO`1U¥ˆc,-]óô[XŒëÆëQÅ2ÒÒ‡bnaž?g¤g¿àŽ* d¦g4Þ²âq[‡¥[ŽÅÐx4L5_ÍN,=–ž4G(³_p8¦¥e¥g7>>¿è6 ì2Òú¨_Ýø´LÕÇŽóñ……E—c,-;#+ãìÂ\Ü嘓‘(`hÒôÂÍÏÊ ¬j>>?çö“˜“™Xlrvš?£Làp¡ñè&þg«qHÏÄ?AÅÐx’Š˜–Œj äŒÏLò缬œô ɯ©¹þZ˜“Øx”Gúœ‘¹Ô¨Žy9Ê*æ²Jóˆ¹ÎÉÌ œÇɹi‡£ ŽY(æ/ƒs sózðÓõp¡mþb3óhý,}F“ ²óüe0˜Só3|4 U¡XÞÓ=<5ÆŸKóŠËLÏÏÎÌ»ÓÓ ³ƒG¤×š¢Ü¬ìÜ ÉAïä<–å/ÁqfjÎሥQ4XÒ“³SKWvzfnPÁqtf‚¿Vä—rœ˜š_Tâ %‘™–Q Ô9Ãü¹8·0Pç€ãÈô8­,(]Š#$:Òž™™Ÿ•ë—ˆÚ¬^¶YéÙ™Y¹™}ÄpA*hÙæd¨qTM˜kÖ«è`~v®¿ Æ«cv^qÌÌÈÈÉÈ”š¥ÏY™eyóÙ›˜†äàƒZ×™E9U-ÌcuÌ8}Ì„ØrÄpÏN‘YF±ò y£Ñé T·3ǬâÜŽ³ ó㳓sÄ1# #(«TH>Ô/æKò —öÀÄȬ» s e„y¤>bùdçÎ#Äs=¿°޵õèçˆ>biu@üò²²G“8975£çã‰éÔr¨jVë2.eùÕ š‡>q8fæŽ*z×7>È_Jküe@´-nÇadÑ0,¢@£p{¨‹>`¾WV*LLKÌô’ßZÁ,bTQ 棊¹. â)…¶ŸšSF • X í@™±™ ¥¢m Ë"¸ÐºGû§]…‰I Ô«à½Dfâ‡Úç4áj¹‚¬¼Òü¢@Ž]ŠãŒË±¸l M~s ?×WŠ=&ËÖá˜[YP8A#½ÜG,ÿ@MŽ&uŒôñ×u• ­êBI¬J¨ñ¼ÌìªÂ²@ãÞ1ÒËÆË¿<ˆ#Ö5¦{ZƒD±¼ …689281BŸQ¬¾t…¿ Ú389<>£Tä!Ðv Iw†{øë†êU}윚Ÿ¦>eçW”öñJo+n,­ Ô„ ’|K{8|1²þ‰aˆ+>(Ž9ù0C~ލµiû˜—¥$0Pr†Pfz‚VÊT–*“¶ÁÎIw‚ª K!9Cq©û&ï¾V—×b­ùË@$Ð*R_Ð6 ?GGˆ=ºÇa¡ ÒþªPÓöS!ê«w|ˆÕ𴦢Î_;Gú Wñ–kveGhËAµˆ”ä`iŽ…þb¨ e ¾´—»²¤:ÐÃÄšPZBYuaùŠ¢ È<ÌФ星·¢¨<Ð-Ä RçgÉo¬+]ÈñFÿj܃ª (°‰+Í-¬)®ôsD{ºÇÈÍÍ̪(( t™`ý¯÷Ýæ¯»ê7úËXZ÷võ[z¼jŠ*k‹+ƒªšìGûÇB(U´¿0@V!„j­Íª>¢L ÂÄ~Bˆ?þ?–OCY°á;yû"ÞP½:оtö ÂÂhM5¾²$˜cÛPZg¦ K»±¬Ö_Ö>äyhR÷1'¿º°,PECwº*Å6®XØø+=·x7TWRY ,v¬í<>°j[`!þGŸ¡L6-ÁñrÏÍ1×o¯+YQÄëz•Ü{TU_ZhC!„‚cþæšµþ2Pãí#=X¶øTX³FMºØuƒ¿Z³#°ñ·:Ð*Ô ©BW¸S8zó,ÞR».P/ai`­‘ú*/(H»3Ü}g¨›>C—ò¾Þ»y†>`ul«]Ìq´¶ƒF‡tš¡ó×FÜ ‚©j\Bìß¹qš?o_¹>PB}¡6úŒ(æ/§ëzÿm”Ĩñ’œÂuUÁîÄÛ×O%8Ö5—qÄ ‚µ¢Ï(°£nC Çk}·G¦Àqª [_ÕØøÖÁNSUåÂ"T)”it|ÚÒ¼ÂAAgÛ¯ »›ÇÕå+ñ?è%È3í1Ñx” ô0[úÚF¦Æ`þ2±yÉ-l®^è:žG÷J5°*8Ý~™¿>Ù| °ñW{[1sS`„A€ õs„Ç ‹kkiãˆu¸Ð°f{µúµ”Õ+C™À†¡*¬5õɶÖTÖ5UÔ6ìÕ+¸í=[pìÖ»Úê¢rTå·hðŠoö·÷Œ âöã°Å shjôÎj°´oŒb A}D±®Q@“ö5n lü‰¶ Cî­­¬_äEÃi‡èƒcƒc 8­ÇëýwzÆȸ£U›W4e1o»ÕJŸ×U5úíàˆõ8¨‡ ®xCYmMgŽ×úÚè3”j QÀ†ýb÷ pć‚œ|Ô¶%HEƒ×±Ösüõù-ûË€°f¯¹~ª:¸z{ Ç ]×á'@ fçÁIX_µ*ˆãÈû‚ã§·<ȱ¥·­Åí#f Q€ÇŽ2p,Å1~猪¥=Ž·Fá3[ äm‰ª°s‡WŒÆ7W¯<*üùù7øóá¦]ûpd£zqÛãþ2`„¥Ý5Ò‡ý nÉö•ÍUM ßì$w¢² ¤¶¤jMy€}k°k–ŽQÕ†ê5g&ïÞ830霶Á_ZÊ3ùɹ׸óCM»]Gx/hY4(œuÍû˜ªþ‰!ú¼iEÓRôáoùóv<XælûUT— ŒÐ¤õü1ªºØ0>è ZŠù«‚ª‡CÞ¯QÕæš¦ÀvU—»oÒglÐ]·×_Œ íÛõvµ(· ¾djóCèUX¬(^蜪 ްýãCÕÕÇ²Ý ›ü}Ä_/uÝ€gei š$P}×›×O¨OzgøåÝÏúË€àzAQÐg¨ˆ-µZUA/Ñ–6ŽP úB±×[ŽóׯîyÎ_Ã-· {4ôuOÃæÀªn ´w ÷ĬF#h†°:ÞÕþ^LOÐá5;ýe — » —ð¡PkÂ@gô›+GUœMG÷ö4n4ŽÚå ''âr@™ÐÒˆ…ºŽ´ž‹Q!+¶”oß9Ú7<96½0›™–Q˜“·0Ãç÷bï Ã^Um¢3³Õ>4È·‡ŸÐ:ØA·”{<0gê¼:ŽMtF^fv¾þSŽøbs„ýc,ƒC…¸Â.{|f‚µÐ*,ÉÀàv÷p½(DÇ–<°a´ã ¶´ú³<85ÊÅ·ö–Þ®ÎÎÏ-ÚvZ,–£ŽÇsƒcÚdÓ°ÖwØ¥Ò‰ÑR þ‚§ªÐÇ@m‰Q‹/P<³¬|ÁÑ0ÕáãXFZ|Qã)J«…6ÅŽ«Z´UŒ–éi* ½TÐ †ªsZæ!fû&@,<ö}÷0:•‰ÙÎèVey :r¿TÀºpÕÆ„@~o)õØ‘À ý3´˜(–(oÈÁ8 Ö˜‚_ðW¿ÄÛ:´o[ž¶©ªÒ<†zâª[¶ 7*L¬ A(ão˜»ªu ¥¨@ñ¸¯*³¤Zù¶YÌÀC ñó‹ Æˆ)mž–áŽU[úà~i\…ÃT‡¾L팮ÍÅçŒWÀŒL9ªPŒ–÷ë¯ùø<˜Ru!¸ 4>îN7Œ¨{›A±IPÐ~޲$†=0âššŸ‰»Ó‚«˜¸Š@ÝÒÓ¬ 1A='û–² ‰x|~vnà‰0×ÃЪÜÌlyšéRGÿV¥™¦åeæúãUåóïwJ,=•ã³w7ð鑃&-5ªØ³è`¸ŒÙ\¡ñ³ŽC}„Ûá?1¥ˆ£ú™š ÿaÜÌüÜÄlTa»móŸ_€)‡ÐÐ$ÿÑü%B𩤡õñçÀ3/K‡í)Reé°ýR£ ¯²J< ²sc ç¡©Qþº´·4ÅÑ 0]=ªÇXÚÙ™Ù裡åtp„¿úc Ѓ“ÆH¥ƒ©=vŠPhEAI S‘è¿gŒ B“XH›ƒ—昜éùH ¡ÉUðÛ bœåÙѤ\ÌÒ¼bÿÊídq-Î-ðãÂ{ž5l…'’XÝ=n¤ Û*ÿÀÇøÌäö¸W™@$JWÎJ^¥ƒcݽæéT.ÆÊXhpV—×ùÝ€Þ³_´î uCòé³ãˆ¦¥cÈ3SpÄXù9®¯j”KŠ·m¨Ëè#æq•ECÞì2T486UÖùÂ¥nî Ž YúŠçzsMS±7Ü ŽmƒÒ-!Ž é„r¾ÒÓêõ¾lTµaÅi_ºFûÜã3]B3Æ$ú#+XÆçæo­5ã—X_—znþš´iE“ä…ÃÑ,ËýÏšŠzèUÙGŒÕ¨˜ZZnªiò/´s×P’¬Öþ*P m°‹‘vLM•õÒñÇ‹]7\õe3Ç-µëü?ì¸ÊŠnGÝ¿‡‰EÝ1Ü+«Â¬«j”Jº÷B×ué[ÚTmZ±Fr„hAÕk«PsXÝëªV{ èÌ3íWøëÍû­ ÂàÓ™#ª[S^çÇaí_ëkKø ®HH%€}DKßméI´ íÙ\³V*¬}Ìã¸ðÛ-Ú^×ì÷^½ò>ÞÓ¸ÙX>àxµ· â*pÜZ»Îàx¶ã*ûD¨ ªUnˆ°®¯ö´Z^ Œ;B5ÝpU4êÙ·*8~y\Å/GÝz–BþêÒ»üù6?Xæzßm6 p––:†>ÖvnÐE'¯«lô‡í¡âK$G úÄnÇt‹hb‰?šgéäKìA˜wÔ5[M¼õ!ýôÖGª u¡ÃÇf<6íÎú Å>\ËÏϿɟ¯Ù‰ …Q+ÈQ&.¡=X³þPôÕÞÖ«.îªÒï}ýìœM´U¤ =‘6ŒÀù®kŒAaŽ»ë7ù­í;7Ï0’~cHlïCÛ[Ûƒ`ˆ <¼v·QêèƒÖ1¶òðû—G×íñïÑ~t6Û{dÝž@Ž*ÒÖãFÚ "màxôÖ‡ .)ŽQòHÓNÉrmiüBèù\ì¾q‰c{e¯ˆíÞ¸v¢ßµ}›ƒÂc2~ÆéjÁolÃß»y†m(õ.ôCM»ü›÷×[ŽsI(ÕÀC€ÞñAiûÃ=`€q|çæiyDci$ÍÁUÛ%ÇöáXÿyï^*zwÃ&yfrúÎe ¢µ”¦ïiØìÉ)¥Nn[¹~[êôÏ'^v?ÚOo8Tíu1\§n_’¸j[;^³Cú0CScGoU}–½{lý>iÑnô·Ÿ¼}Ñ8ßÃêØ×¸Åh¹ß8FÁ®.ªxvãáÀÆÿúòQvù ‘ü8§ËÝ7Éo”çÂ(&ýmìŽß½yFnÐ,ÝG̸ßuÿÕ¥÷z\G•ìôÁ4/u߀EOl]Òè„É>ÛáXm0z~³ ø€þÛ«ÇŒá‚CûÈÚ=ÆÁ)JþòÒ;üõÏ}Þ ¢Óí—•Ÿ ‡ZëS>ˆ êyõÊsñ9KظUPG8/_|›¿þÇÃ_äxêÎ%H,}ÇÏøŒÚ7¯Ÿ”ïC‚ÖW­:´fG¶É±ïÞâ¯yäKFUp ÞÝ=ŒÚãÍûüп÷ûüù…mB«á¯J3ô¿=ôe£”ü-Ç™#xÁ¾Kü+¬Ìèãö•ë4íâ¯pžQæªwiCŸl>à÷Ó~zîu>mÃÚYÊ3ùßþWþü¹íO¨Vp|­åÙP>ÖÂ,C*üçr?þð·Ìqÿª­û—ðLþë[ßåÏÿéѯGH×-¯2Á,ÃU;Fz_ºðÖ¬w¸ ßžÞxPîÑ -%—KÿÐTÉV§$}q×ÓFèÞ_(Žžý 8>»é°Áñ/Å«Kc·àˆJ¾ú7Œ³!‚QCUÒ|À±|åòQƒ#Œããë÷§hÛ÷ÏüšYþí“l,2{_X;‡} -8–¯\z×8bÚR³ZÎàˆ½Þ÷N½Â_ÿËSbT›mcìCÑ»ÏmRîCa‹ßºvr6>sÞøVÿ@Âñ0*„hýLc¹b2õ‚¤ßòíë§àôÒ)=½°^ž_ŒÕáߣ}çø/(l vOm<ˆ`¸ØuÝq9b±ª‚²Ç–p9àz :°ƒØ†KºŽ/_|‡š…ü¾=ö/ºo`¸ä{ö™iØ I`bvêlû•…ÅE÷^ý~\c»7:=q±û:—ñò°ƒƒÿ?63™,ý* ö&ò\»3,:jãÅ 6”ÖÊSïØ`ïÄGh"±õ¿£g*‘ª£¥ 6´Ç¡ ¡”_Ó¢·&Üb±UåæÖ}¯¹øB¢aú%yìÔü~/©$šˆ ……ÃÑÏ¥">üùE‡inf@¸ z~j~†ã/Œ¤‘ÝÄ_ÑÁ¹En¼#>(#_§_´g2&qªcèi9™Y2\…¡˜_˜gD¡7Ò¶-8qaÕË4 죊ä ìH`ìÛ8¡é”F0:Nð˃6H J`ôÑ_€ñòðn9׿/ó{NË„±¼3ä ×™ÈQÌ#X¼¡ üÓpìˆñ’Ä*Õ¶lW”=Ø[·Šõ`\PÍZ¨ªôtcL±#ø“ ± ˜„hàÈ¢TNæ˜S+ßS†¾.ïä±#¨|v~Öj•Là¡“=˜0ækس”`Gæãq~OÝ ?|äÅŽHàˆå• ¸A\vÝÐÎD˜ óî7ìˆzå}>xý ±#ôf¿|Â|1\†ÛŽªœqµWöQØ? "v„^ªökr[ ¿1 wÅŽ LÏ §„ë‚ðc@ MžìHïø`âøÌNhs¬ >¢…^âè¦AE9¼{Á2õžSó¬cl ½Ž×+òFȪP²Ä,|ìHÇp¯×¨¹ñ*æ¨àJºÝC1ƒ0ãÆ+¤áؘ¼;C=†yÒ!Æé$0asÅG!¥î QY,êÆòci‡cGèõß~ú%rÖr‰,“^«+VGÈÌí¡îÀ>b¬.063Ñ£ß?ó5_ÅÑYó`»nD—‰ %°‡aŽúØ%Àg‚üÔx§à®Ø‘ÖΙ ÃŽþ˜V8vëË8¹°ÜÒk*êØ._ë»=ïC…GŽEA$ÚDtYReA«DˆDŸä(Fd}u£±Ð±#“³Ó·=!&Y¸}¤Ç1y¾ÑÇßà˜ìHûPÏ ŽCÇcÓŠ&Í™ìÈu‘½¯-5k 7&;%ßæ‹ S½˜kã-ÿpìȬz+ñZ@UzOnÄ&ÚÛ*Sm1Á-ô¿½ŽQIFû¬ ýµqEâí½;®Îù´ð9ð-qÙ]bÁ`±Í‚çWö½dï¬ßh˜¿”`G WÆ¿ÙËrêÎ帹iRµ¢¶-µëè»8~rK¸Œ×U5V{½pìˆâxûâ|Ð6 šp›[”£Ô2ÂdéP‡¬⯠À¾U[ _:;Ò36ÐÒÛæ¯Êò¾sÿaG‹È…æÁCX½ÝàŽiìlä…æÑMXà%®sx¶ýʈj¶IP·Üà=ñ^¯§ì겕«½á„”`GŒè%[”äÂ7:ܘ½Ùƒ#M»Ø!÷æ™À-a¯ï ÅpìÈÅ®]£}ü,ëáµ»‰#v7oß8màlˆPÛ^76‰m‹T#’¶Ö®“&ëÅŽ@/±-3ÆâàêmÆo8v~Ëë×qqY]}iµ©½+väè­ Ø.ö˜Om0³5„cG`8–ZÚ…“ÇŽÀé2{LÏl5¨<µÁ ’¥;MÂioÌ4}nûì$ÿøÜkŽíµì¥yE¬Ä$8{;ê<þ^J°#ø ˆ%F"ÁЦê†pÅ™ /l{ÌØ„cG ½ßÉ„keª ÓŽ™[˜ÿþé_ÏúÞ£³´‡öˆW¤;2>;åÆŒmËk;`b =ìœÿ=õ+ÿ¯Àº¹j•н+vä»'^FüNv1_ß÷)ãaJ°#ÿ|â%¹aÖù%œ‚ãâ~‚[¨)h‰û¢küÆþÏ›”`G^»zìJ¯{’àµ?>ð‚Á1%Ø‘W¯¾¥Û³±"¶Ø|ýéÁÏÒþevaîÛü4p¶iÅš§7¢Ï°PK)”ټ“2$;‚}t ãp8Ö4±æ…Ò -<-§O_Úõ4oè¾æ×.vÜCE9ß<ì¬ÊÑ™‰<úãÀÆcÓ÷ܦ#òIJ°#Øî}ëè­ ú°*ìÉóqWìÈß¿ûƒ1ódUúøW}I4û7Œ–`ìX½Íðl û"±#1¥6+ÿ`ó£ðý†ÉN`ܘJf¤§iÚIÉþ±sÁôém{LbGP®"¿ÔHsWìV¥ÐØü;==}{í::;‚}¹Ü{“î°äÀªÍNIC™#ÏØªd<"ÌH¬._é?{\6ìŒ;½Ô*±#–Ìù³|-vŽñ„÷¹•S?›{§T\L Üÿä‹´î“sÓF(‡~‘ž–°Æ}/i;2ÓÍ(mJ°#‹¶í;_r$--–ÈÂÀÀKÌQ EöÑ…Øœ`Tˆ2‘å"숟RŒ ¯fÈ6‹™bíùg<åôŒsöp숛M$ÁBÖœFÉGôúqŸ;½£vÒ#lË` šjÜÎc.³P숓&ÄNü\ÖFºÉV¹=­ò–Aã_Ðw—ˆNÅE¹,ß-ÉcGÜ¿Ú\@NAVzÍÑôü¬='ZEy2¼u¦;297c»E«ŒDF†¡z±#èÐøì$$šwoY²Ä5+t;ÿJ8’<ß½÷v„nŽà¯è”Œ”ëk)<»ñpìȨÎÄKŸ•HXö¢Éò¼bi<±#ú¯Ó¬‹P@*ÿ% "v„o%°,ꥑn!ÖÕÞ+±#uú+kQybX˜“ï‹Þ%‹¡kø+ôƒÖŸÎŒ•å;ùB0/¼ Ótf)!!±ê¢ ˆ„Pç„°ÝòTåϧŽÁ_gÇ Õ0þš†ÝŽTÂáØ‘‘©qykONf–ÔçU…å$ÿð›w!©î$¬$xÕ—VKŽáØüUŽ*4³äXS\IšüÎP÷¢s­ sD)í6,EqˆðC…êpÍ8µÇŽ´ uñ5géé‹Ù ¶Z½W{ع9òÅbTH±ž±AÞÍZT.mlr ½¨üöP÷¼+|ÆC÷ü"‹B”¡;…çÒ5;ê#¶.ZÏ+ óslª¨—*1;‚zäkÜùvV¥!!ؘ lÌÝY8;iowáq™ŒX†ô¾ fr³ŽØK^”S à CC°#˜µß^ý€¨8ìñùkE~Éá&O,$yìtû׎'8zU¬­1Sˆ¹ÜsSzƒ( ¶W®.ö£C’ÇŽÈ¿‚qä£E¦òËß™rÍÜN:â¯FÐ:%Ø‘—.¼ÍÊŸ]Ž6l%I#vŽo,šÚ+öøBÃJ;Ò1Ò+o&bMHpƒA:`÷Ù3ÁBƒQ[¶·=žŸ ¿"ʇl¨J]&ëngàH?µá d)_R‚ùÅù·X3Ã…ž[˜ãCðúâΧáý¢?<û*ÿ¾zh<ôùC"9„u7ìÈÎü†Ítâ8/Ž}ò¾¼ëY8;r¬õÓÆW(ÿ˜ ï.:;kÍ,=–Àô…¶ösñ…9qLA@§y1u‚A¡}ñ½'J+aÙ™Ù2ÒŸìÈ‚ë‚Rƒm÷ýŸÂ"›ƒ¢4oà>æî™Â±#2c… bM"ìÈÝècÄŽ0Äò>2¦À˜Ã2ä@ß]äÀl牔›p숊'% :jKd…:ÕòŠ©À‘ŽKl·U´ðËXG§ŒÄ;¨Ê›hIì]1Ã=ÂjÇçx(èT}/—RWUÅHó©å¦‘¡© õC “í]áÉcGfTÒ§õh8& nêh@ þÍÍÊF¯gçç oê‘ä±# ñ¸t9°[Çé¹D~Ô)9>ˆØü\†ß°5°ËãWlŸÐ™t„²]MÍÍpgý©Gî+ìˆL:‚¾ç¢×^Öž›2–ÆŽ`Šå ci^1„alz‚EÈH=Ž˜fœNAVa¦dŸâúÃŽ@_ÉS4&+#kH_C¬Ô#áØìgæ]-Š–æa¦k]´±¿L;"“Ž`ˆÐԡɱɹD¡gøÊR£¤.qìduù/É+ ™g$ºÝÒ7.èI=‚ÁÄu&Fµ¦XaSºGû™#ÄR®ÇpìˆLR¦2ˆä£U,´Ð‡ðì! ò‚‚I’£‘z$;‚Ms„ߌޡ³,´PbÕEå”tÄr•ïêòÚùx¼k´H©G°g“?D×F§Ç&)[׸‰@ˆB°#2鈥ßlV÷¶Œ$8Rê‘®±~üC—¢kØz±WSe=~r£?‘s qÅÆ•'”R '~hã‡k+PàöP뱕ÅU:Œ< 9Æ }ÄYà‡ëªܤ#aG°ÿÇ;CÝR„dê‘pìˆN:2ÇA/L¶:4õ§ ÁŽ@-kÙ³é‡ë*!N&Ûg˜Ñë}·ù"*Èúˆ™×W©ÊTÕ “ysàëÊZ‰ ëÔ¼¶¢Ã%U‘z$;ŽNÑ\½*=–~½?‘Ë¿"¿$‘tD­¯l4Õy7‚‡×›z$yìHÛ`',¯­¬‡ É>nU/s$Ä>y줋º³ ä,àe¤åÁŽà‡t§2ÑîúMðˆÒ] ’F!;b$X¢@K_«/#õH8väR÷ þ!Ä ¡¬¦u°ƒ•‰?õHvzÉY_¶:pÜ^·5_èJäÕÀa…ʤ#˜¬›nφÁÚ¡~8-_íÅñOxi7êÛë¡T9Æ€š·­\‘¸éh!¥vyS$‘IG°ä·×5«Ë¤…Qê‘cmøðsex¥·uÈ]¡ÐÀ«× NŽ^uß8´ÔYð6u}uçu¶/Fê‘pìȱÖs :\¯~X~¹ç&Ƕ¡^6­hò$ѧ¨ØJœïlaŽ”z£Äʲ„À*c-³k“…`GTÒÈž£bHðÍæšµðR.vÝà£|hÈÝ¡ÎxCG!ØXùÇÖîÇ“Bh÷6nöÀ¾ˆ b°®²Á IxínoÒ¥`|OܾàøÕ¶þ¡@ $¿$ßÚß¿j+üêc­Ø“ÇÌb…^ëm»íJÖþÕÛ ˜ÈUÛÐT™t\ N?ìh¡óq[ïq®öÄB°#œtT“hõvh<ä”zäõ–ã®,Ù˜DÃÙŽ+¼^`hvÖm„J¼Fiz~öDÛB)B"vD&=¿åa¨wnœá'{6K ‚1’ŽìmØŒïß:ÇzÌH=Žyëú)þ!DbKÍÚ³WÙjÃå0^· ÁŽ@!°@÷>µá ¬ó[×OrG×í•[¹ä±#ç;¯±Bͯß•(“ô<¾~ŸÜ2,väÞdïhÛÊfÈÞû­v8æÊßP˜ÉcG~vþ 渷a˪òÚ£7?tw+6\èÃM;¤#ŸÝþv o^;Á?4R$1’Ž|nÇpù|`é<0»ÐK®ãÃÁšBø…OIŽÉcG^¹ü;«phá}k=‡œ°#àø¥]ÏIG0Å0…¿ºø.oµ(õd˜ì—­€Ïn5ÿRiÇÈ=¿ùayþç¦ò§I;‚…3îZ´múÌ5£á)õ¬À÷˜àû> YÂÆ¿iÚ‰mÎ{7Ï|èZmüð+»Ÿ»Ò{KiwÁ©G’ǎȤ#°t_Çž[¿½zŒ üÅ‘/ÈýKòØ‘—.¾­n«qN!ê?½õ8coß8Å(eÅß¿û~òôƃpa³øÀ§Iÿæ #+Ì \‹ž}•7w3ÕÁŽ`ãóßÞùýÌÖÇàÕüàÌo˜#¥ÁªaÃò×¥obÈÑœº/l{¾ßwŽ¿Ä(è–g7&dû‚þÍ#_ES¿%’޼¸ W|O\sƒ#Ü .U”Sð/'_v’aÄbPhòÄ#;òOÇ~®a ª²ƒk¶Ãu|íê؆PL¬_Yþ¾ÂŽ`öõ̪¿cO ïƒÓ°<¢•ê;j!8h˜+VcIÂÅUG@ºí…¹Îpì”Þ𴃀uÆ>±gl°]¨gúíõ²MG §C ûåîÚÔ¨B,± œ³ õ¤ʰ‹ê¬Õ…¢4”®ð¾eÃŽôŒÌ-ÎÓ‹ô?,ãÔ|â #õÈò`G0ª£3\4vZ, æŒÏ´ÑS('éˆnPF,-?;Ž1½Ò@¿¤Ô#Ú5J¼ì _QO),¨i¨MGiç(¡F2¦t_ð¢ÿ"þ˜*¥;b&ÆñcGôÃEï„iÌ‘í×4ÿK m–4ku1’d‚‰»‡’–F$Z%î-ï­Á¦Pô³í6•’pÃø"ù®pº÷º¦ìZÅhŒdf†NKˆAáÜ¢…Ö°)’.Éû,3u–Ô3'–ãÂ&‰Aå®eëʳÑZôˆ›aë>joóD^¾…îHœØµt°Š²&ÈWV•¯t± G;"2‘`.äŽ(;—TÞï_Ê"!g;ÎMbk›R¯çÀ/éb¬0ª­ƒ¬©0€ãq#¦–FQTÉ@v{ î#~Bçâzõî`eA©Œ¯W””äaíË‹TH„څ䬭¬‡®Àñ±¤tuùJ‘›Ä†Z£QU×ÓÌ'"ßù%-"Ú¹ƒ0@0ÄM˜ Z´Á•veàiK‰qB(ƒèáØ‘+=­îø©î¨w…ç¦o%ʯ­l -;Ò6Ô¥ MH'bW{[Õ¬%zTØÒÛÊÚÝ¡²h!f‡IaÐ7èƒÝΑ^Ö¢øúØ*r“`iÏ&c{ ©C°#½ãƒ¼ØÑ_¥ÛC]¬¢ahËj¯õßæ…P]PN‡Ý2]z$BòØ 8_Ý…ŸÓŠ–é rÞkݓŎœWY4œ…†¥‚‹rNôq]Uc¡à‚Á²X*,ˆ~ÍåZ_Û¸ ªQo¢$ʇ`G0õ¬°Gß=-Ñå–‡^Ú$Ò‡cGdX!QåEÞæm+×K#‚¹Ò{Ë9µÕI(ÅåÕ-X&P&§t€.²h¹«É¦A12ž æ’î×À²b_¡—ÄKÌ/m¸”J'@$* ¦6yìȹŽ^hø9Õ ƒµ“ìÌ,)–;êš±H ¤Èá5;¡‹8´ƒq¹ÐuÍäM¤C°#£Óã„Ñ¡fïmÜ“×9ÚÇoQÃ~\½_ ÉÙœ×ÓÔ–TaÑ¡;ìã+TåòevÆ X!Ø’ºfN7 ?Ù®óaœ×Ó¨òåµo]O^o¨^…©Ä::uç?„HÈ¥‚Á80ò þ½ÂÎHK[v(Ì7Ý€–­£#KXÞ³ LáÕÛ‡§Ç¯ˆ[“è(Y¿šÖI¿,É+’׺'H0†SFQ¢k½mwDpwæÓw.óËâð%šµrøíÕ¸žÍ5kQò½›°½°N£Jrò´÷ùìVZÖTÔ¯u^aO”‡æ„ÿ ï÷9´zG¡†äÊQ}fãaq| ãõmÙ놼ÉÄ"vÎ^4œÞ ‚1”!@Y>;wR,„OoyÄÒÓ\Fö‘u (C8vD†ýö5nÁBð–²ù€Üú…`GŽÞ<Ë j†—w…[j×ÊÐQòØ‘w5Sþ§ç^ç»ë7É—_—;EôzK"Ú÷Dó¨#˜ã÷o%`g_ØéC$‰éŸ’ b ó¡=뵸¿´ë¬;Κ†&ÑEo^;Éá1x/ÒáI;‚5ÈQ[/R˜(¯ýIÕª-ªüºïN„Äö¯Úm “*%ó‰õ€HòØÇÜÁôSy>ÅB7~ ‚_Ûû¼å^Oãö¨ü© ~{õ¡í5F¿Žn7ûé¹7øå XU I;µÌWµÂÿ'_è;Ó@„'X€? 5ÀC†ê*ýû?½›@>¯1:ïÝ<Ë,ð•‘ä±#°Ôì A{fÛ£–†òpù†ÒÌéϾÊ?'±üŸÇ~Æõ<·éˆtàC°#gı8ÐÞ/ê(ôCáÑI•‚Nö‚FŒ0(ÏV>+=óû?-Ë'‰éVX®Áþ£ý/€#½ñOàIÙN;S"qä‹\žz]ë-Žùs€ß>»é0–v—B~$Ê}ïó2Ì™$v>‰^8¶[ÃãpŒëiþúá¯`ÏÂÛpÇŽ=Øz•ÅäYÙÂ$±#§ï\zCl:þË“ òúµã¼0¡Ã¿ºû9.‚ÁñÞKLÙW÷<-Š½Ã¿¹åc±êGc>hý E¹ßÔêúœ65(ƒÅ"aš!Øx•?Ön…,¡² F°C­åxÌahýÉåPÜWؑ׮‹Ûq e¯­¨§\Ø11vdW½ºN;YÊÉÌnìB7©”ñÖD8v„ WSEüX,4}>æplvŽ€n3vdûÊõéié°Sî«§1,4(´Á9µˆÅ ²riÃØ:Ð99?M,àJ§hÙ°#w†º9ÓEeAInfŽY¨)ª‘¾åÁŽLÏÏLÏÏR i±4¯˷¾ébÉÙiç”#fe§gR¨”N“¨Z°#^ ‚;byá#vä®t_`G,_–‹wEšüØË{mMv„þdbG¼ÉpÒk,Ü<ØeDfÚaìH  „è^±#&â<\ô`GDÞŽ`ì¢K¿Bgåv$[§'ᯩŎ8@?tFØ ISXç2B™ž„º“ÅŽè Ï‹!Ø ò cG²ÝûÏ&Äà Iz†„‰ÀØd(³áIOR•—‘ž¨ö¾ÂŽH8ס©Q^h†Å ÁŽŒsb@M¤ˆ~@äÞ±#U:®ù‘@„;B0þJÄé¹™‘éqž,& ÁŽ`E𱑭_† Õ¤"@n]@$Iìˆñ'x¥”K_B0 ÐK„ÃÓ(IìHšÚ™TS–jiqN¹qèQ ’ãˆÜ#vDÃDÊ݇ãâá=aG4L$‘l£¡l´¨©-®rò»P ™Ù—€~HtïØòþýá[“Y±õª'I€ü³ÎÑ«d" ô‹ ÄŽT(xGbèB°#&ˆÁCˆ‡Œ¯×)`ŠRò:”†çЈ¥£#–F°É¡ÆÃöá^·16Ö)Ev%v«jAféÀ¦šÔ¿ÀD¡dÜ…Œ±¼‘ìþäÂD(Z£S|/È ==ä¯!Ø‘[œÂ+ˆú¨%ÓÔ#<ÌËν=˜È¶ˆÁCìpø¬?_]v£ 0 ~}œ°#ÅKç=Ò“.öjðD*Ïìd’0ßÝ©J@ =;‚‡x¹” &bi½Äç’*ËHíú“·/ñN*¨®Tq„rËöD’ÇŽÈ8k vOÐG¹éQœ4)Ú¿jÛõþÛü+XP’a¨žGX@DÁŽ@ ÊXèÔ–ñ¼Hú‚‡X³lC±#E¹…ÛW®—éý&"bLè’2¢ìÖ¬²‰ºYÕ:¡ˆåÅŽÀ¥i^±ZÜÀ¢‚OÄQ†4 €Hväl{âOП„ÄBæ‡u¥+°69–`ëUKGEöñ…R&Ë‹=."ÉcGð'ÇðLDhª‡.ª`ÿêmo];9ïŠýšŠ•¡?ÖzžýÔ C/Á7”‰ÄÀŽ@K” W9;"ÿˆAÊò‹°Ýö3:Ð_Z¢ÓžX¿ÿ|÷õ¾1Ç”h,ÈK7Õ­÷!уˆ9&`"{ÒÆ;‚ý‚ «„`Gð§áhù±#êáÖGøsvíÛsphͬ>x¯\~ÏxÈ_ï;Ò\½Š–vàC¢ä±#/_|›ý™ .äkÇY§mðD–;¢ÿ”UŠÇã¡êç6‘þaj±#´ëzÓyè`G$L¤Ò Ì>$J;âÂDbGôÃý;ò¸ ù7ñ0µØ(=)á¨ÜÝ=õ+>}rÃì=eŽ4?v„JìÈ6÷²<ìw6)ÇŽ|ïô¯ùÂüœòÀýFJ`²« +^½šÐÆØ‘§7B;Â0‘5 Äò>$J;òFËqvZà?»IÕpVJ®òÃç6‘0‘@ìÈŽ•vÖ'ª ÁŽ@ÃscP9)y‰Ñ‘„æÁŽÀ7¦h7ØŸRwph€HˆÐC¢ä±#§ï\.„ýMJT“ˆ$‘²‚°#–ˆ|Qp\;¢þäÂDl¢¶¸ æà‡g°zÈ_“ÄŽtŽÐŸÂ°#/n{5°B0KodŒ‡ÿíïqtDaA•§ñ­÷47?Ÿx(Üä±#òOØ IT›&ï+ì,TÌE9À^ !±#ë«Va‹§“9Øj ö€çDjéøÝ;v„N9,çEvd|vJò¸•üzhrÔ=¥TÃsŸ8:‹ÅªÝÃ:‰ÁήAe,vdf^gwG £HY숥ܯ]=ÆòÉØ‘Sw.±ŸàÇŽPjýÔbG ì'Ü#vdoã–ýí ™b˜ˆLFòï ;²ÎM1’BìˆJF’ê{ÅŽ)F&"c÷Ž‘ZìˆL1Â0™Œä¾ÅŽ‘$±#òOÖGÄŽ\òD>>ìÈ÷OvdgÝÆß\I¼ð½ ØãO÷‚¡#Vväg~Ã÷E.väŸEŠ‘{ÄŽPf?v^¶Zˉ‘ºGì§I!vÀÁñ±#êOÚ ²Ø‘€Hj±#ü§bG,ï(+väÏ}.;#+µØ‘€Hj±#Yìˆå&#!ºwìÖ vs¿v$;#S®ß$±#Fj¨û;²×ÝÚHìÈêrµôÚ†:— ;¢€b~ìÈÄ씻߹Wìˆ>Llº?AìˆåM[~bG02Å9ؑɹ™8Ýü„¡@;’“‘­£É‹÷vdÑF3> v$¦’‘|dìHléÄü9ÂŽÜ•"ìˆóðÁÂŽ¨ò‹Ñ)’âÆC—c„qèãÈ;™Ññ;2:=Î}¼o±#p8¤ú}ÆŽ`ØùøïAÄŽtŽôò…{7v³ ƒµÉcG°"XŒ—;ÒPº¢obøÅŽ`: «©ÂŽ@œÚè-ä;rµ·M[í€ùóŽ@Á6W­J!vD^Osßæ¹O°#eµRóÿžcGN·»×Ó|üØLÖƒ‹ÙQ·k0UØ,OÒÆËƒ¡‹løk’Ø‘æêUÇÚ.ðO>nìHEAi}IõŠQÙ¬ß{Ÿ`G~‡¼#‡Vï¸ÒÛaG’ÄŽ@8Ìo}BØ‘ß^ý€Ýã;Â_±#On8 uT’Øx’rM}$ìȉÛØÃüD°#GšvÉà°#P |¯è}‹ùÊîg±öcG°Ï‚£õ{ˆy÷Æék®Jà°#X°rr?>ìL]Y’Bì¶ÿrò—\æÃŽ|ïô+|b„‘%v´gôh)ÄŽÀ!üÅ…7åÃ;âþ)5Ø8W_†2ÂŽ,'v›øÏvÄ eÀޤ§¥fç§;²¸°x_äY&ìˆåIݯwÖx˜ vÄ¢d8ü'º³Æ¶ãžòiº.eg¤©0¶çÎ-â0‘À‹lˆ’ÇŽÌ-,¸}¾³Ob^ìH–¾žÆÀŽäx£°Ëƒ™[˜—5V’€Œ•ÔΩÀŽÌi޶µÄ5ér(þ½bG0&ó°\ì HX,”Õû ;‚ư°q•Œ›ìÈ” B}ì gÄE6Ñ5ü'ºž†¿R‘%Ä TV‚±ô†œ>0vËD¡">ìH`Ò9”7fAbGèzË‹!@ ~…ߨôˆÚýpg ‹ÝÀެ*_œå>¦üΈõQbG0\Éa`G 4J;‚VAãq™ìH÷X?Gôï¬VÁ^EÆ×Q9-ãν¦x zdJ$võÐi‘ÄŽ`ñB-´ˆh7aG Í®÷%š‡B,ƒï¬ò¡¸QvÖÍ Þ$°#Ð{. Ä²> vDÃDf ìÈ­v¥0]ì¶4·:±#. oÔÿ57P¹;eŒ¹Ø%%÷ŒñÃD¬ ‹l.õÜ`— ;‚ ’z8µØ¾žFbG0¤aˆR‹A—i¡%gºžFϣĎ`$”!;‚ ’H>?vN‘ìHvĸž†°#ÆE6÷޹Ò{˹½[`G.t]gg¡d0&;²µvÝÐÔcGèzË‹!@‰{="ÆŽ¸Ù|,Ø‘ãmxïˆBKHìÈþU[á:Ø‘Ãkv¶Šëi\ìÆæ½cG`iT%vº÷²€éàáåž›²r?v¤,¿ý ¼ž&PBtؘªÍ:š(±#’µ•õò ÂŽÀCxïæñðwÁŽ@C ±#°ì˜µwÝî0v+Wʶ±T˜S]Á ±#ÐN2`Z숺žFŸãK숔4l:Þz~ÌU&ŒyóÚ‰…ÄE6&vZ¿5°#¯Û+7)!Ø‘wEŠ‘@ìˆVy;òÄúý¨ÜÀŽ<³ñð•ÞÖÛ®c˜ÆÎ¿3ì¶tCbG %°²¸|vªþCaýwÖÀÉ¡ˆ,Qv$ðzšÀ‹løëG½³æ­k'—rìHàõ4Ù}"Ø‘Ïl} 3b`G("Ë´BW`¯…'̼˔ Þ9ÚÇ»}¬ 9ï!ØôZr¬.*Çø ÒÃ1eyÅM‚!‚,A«0Ê  ri‡`G0A,í …b×ʳ€ Âú•OJr * ʦ½ EV•¯D%ÒbuùJ}†>4ìÂÂ0ј5&±Á‘î>hì`3‡=$ºyk°C©#7¬N±=)Û몠—Ü º’×uU0yX/<ª )Û!ØKÅcns²¬A ,T¨ì£{ÁŽ`Ä’P˜Q…¯ßÒ×ê”Ö+[šËÝ7Y{7è'àÈáaôûdýD¶y 4dÛ “PÄÖ6}DF:Òp” 0N‚Áèq¯Á‹N—°Ïd‡òÓ¦Ò“L¸OJ1bà(1˜¹M;‚&føÄ:ëBFÇ›«WIŽÉcG®ö´ò©,,èâ땞V.°¥f­ôB°#Ý£ý]îa7Â&-Kº¯«¥íŠ„´n!؈±LY6þ`!p€°Vœ³‡`G,}tΛIIEA)à†“½[dùìÖ¬£Bm¥© ¨ù”ˆÇ¬¯jÄs½ñ$г;ÐK¯qÖœB¨®'yìÈÅ®¬´Á‘€/]x[[4evÖol®ZõÒ…·ØÆéô$ëàp¾+‚Ÿßñ¤ÿƒ3¯òÉî#k÷H¿"yì–3¿-[|hÍpüÞé_sBŠ|G¤'ylÝ^´áfûÑ[gé úò•=ÏÑömþhÿg,5Ao ¹NÖÈ>áï%ê~ïf¢ ¸WÍ ¦ƒu5!E^¹ü×€ÇþU[árÈ+^Øú˜Ü·†`G ÙûÂO^ÔПƒu5ÊïåC°#hÃ÷õ8Óˆ}vûpäà«°C¿=¿Åƒ5I;íý“9»’ýGû_ÀþâýÖs]Ïå >H”üËÉ—ÙY…&” -;¿W(@…Ç®í­ë'ÙFù/ízF¢IÀñ?蛹þîïͺïä<»éLÒ?ý1ïò]¿~´¡¿yä«0(ßéIþ÷G¾Š-´[@x¡/ ðDòØÔÀ I[Ï 8BäX™ÀJ?!;ú?ûmþ ¡Â^çOÜÄl9™Ù¨ÿºêõ"û›‡¿ŽPª$B±XL €ðdB°# oý‘å†,ŸÞx=hÚcmUP˜“'sÌX÷väDÛÅáéQ e7êýËôüì{7Ï0vÎ-þô¾ µÁ¿±sÄþñF»Z/ºöÔ” ’(;£?57CÃ3K»E9ÀGìßã‹quFçbGè4 ž‰ëµªQ…Åï$¸ª¥#€´µiém›×"ü“%·À˃u ÷,*YV„eÔ‘‚ù® /²°ØÔÃÍ5`d0òÍpø!(Ùq^1u§*±m›bsôK SŽ«ª²ÊPåç@^OŠ¡æ9u|áàhrucf8J«°ò@>yìÈ¢½˜H‘ ß緼ؑ4ßOS™H\ëEO,;’–&!É`GdáÄŸ"ìÈÒ”Jìˆåƒ˜ÌÜ ³=½SèN¹”K&,Ñÿ2GáØüiÑ‹D1Òœ¤Çœ«g¸¾˜†>Q1ú%BÀÈCI˜ /¦숥Õ÷H÷'&–¡ êɼƒZ°©q{QpŒ‘ Ãz6Ð0 1“á‚N˜’ÄŽX:fÌÁª˜ó † hŽ ‚v‚‘l†å½-_ÎcòØpœtß™¶X+ň–\¾Kp|±#ÀIà€î^°=éjвóñïi1!àž°ä’ï+ì&e\äMÁ(¡/R Ö!Ø$:ž‘ 1˜X+TåIë²4vÄR1Qez3s$í”1NëÄŽXú€ãý™Ú/¡Í ±Æ€Èá ÇŽ`Ç5pÇÖJ;?+ornjÑv\,pƒuòØ4•ãÐàXœ[825Îz•@!–>(aq’}$ªraȘ>Q, °B±#sakˆÊ!äRV±wE3ð¤}ÄÍ~a+­545Ʊ<±É—“ÇŽ@Û‡zX™ ˜xQ¡$½ Ï”BEJWÜîáí%,ese ÁŽŒ©pn1#ãÚ/ ¥ÿ¾9ÐÁ!½tÃbq9Ú‚¯g;®²}A¡(ä\lR¯òÀâ\î·J•×ö¹í¬Œ,yvi¥;s&5X}x¾TÁ#äÅè#V&4îztàÛPZ£`.w.ñP“oÓ;–Pì{7Ë !ØK½?ªî£±Ýf`EK]vg¨ ™¢º@­A~aÚR²¡@! ™Ú ?„]žIØeu¯d‚B8~ûoz)$Öë&ý‚=Ý¿zþÝ6ØÕæš!Ü,©êéåÙ‡&Üá]˜!Ø,@‘ýBi ´ £òƒkvàßЖmZaŠ‚Î^™#/Ešßo=7“Ð0êN·ëýn¶-[…B¥«™ÿ±¶ Ì õÃ%à.7}C²ìæªU.ö œ)ñÌ¥îœØ}l®^ÝÒÛʈØY™”Ë ÅŽ@Ep+[/üÎÑ>Þ_hPˆ:ƒ>›€˜ØüZ ï‚GµI%,i€½~ûú)~Hv\z­¬Ûc@8ìÈôÜŒ¼ÿˆÓ¹ÑW¸pO¬ß'7k!ØÐk-ÇÙ­‚Ò«/©–Öì¨k–z,;ÒÒÛædtso»ÃW~uõ0;g‰#ÓôÛ±é N:‚ÊŸÚpPö1y쬆D †î±~ÞæÃF<ãm/vÄÒ¡Yö¢1¹=ÈÏü‚3ª0U›DŽ+i숥ïób×:3-êK‘m…À*ýòb"’MçþÂþü–‡¥×šìˆe^>äù ‡âldâ–ÓÈ$Ch±#–¯`‰©å‘ÔH…þËyu,ï]M¾ªÒ F8v$®àWq+¨2Ô“‘îÆ2Ó•”Ë@)=hï7˜øXüÆT%A“´±h†KsŒQ%RMxŸnèßä±#–W]¤C¶žÂ"vÄÒ÷°ÈQ•s#JwˆÄØìäR²Šæ“~_aGt%KI̧*ÁŽXÞkkˆ˜oNFV¡w¦Â±#XÃS£¬‹$©+óK #ô bGæ¼p&[Klµ·áØh‰¾ñE¿:ñ¹rc)%¯ž±þ„‰±=Ú¼¦¸’–|H@Œ%Ñ…5ôÓ'aF‰¦k÷ÑX¼!ØKÍò´oTªŒ k¬»aG „üv²QuNjb%à á1Î|ñ#XøwD|Wxa“À‡þ·gÎ ³óyTouK ¡,[[RelB°#–>‘—XI(Ì‚Ý:ÔåÛ(ùÉuÓSÉD’ øªglPo¡œˆ…½áHÜèX\\4+Ò´¦¢Žt›Œ$@GûwMáØ‘øââþöE;ØÏY[Ù`h×ìˆå\[3mùÉVD*úöf{Üè#l7oG¦Çä¢öö1—GµÕMFÂŒ˜°ã5TbvÄò^[cP©›3t­ÿ¶ãùFdh×ä±# +Ý·f}NÑÚJ³pòØKÇ_y¯hôÒ¸°Æ ÅŽXZ$êEIßUeaØ,Xyþ. bO§xLáØ8]ç:¯Å—pï·­\oXìˆÅ×Öé/ˆ)L i äHâ %£’èÂú|YÁA&ƒJÙM•õt]SòØK¿]-Q’’0 ¤]aÅdÂn’îc:¥Q±ôÅÕí^£ÀŠ «Ò@&…cGèÚš@WãÉ/ßV•¸:Ðë„AK¬qÁ'Ú.ø¬¶CÆ…5V(vÄÒ1ã^qCœ$UXŸFÁk=/ß=ŬÚfldB°#–ÒÌ­fä©jUùJR˜àõÁ­åë’­ÞN»ÇDö&OÙ’Ü"™”`ìûB°#–÷ÚƒvÖolðj×ä±#–¾íBf@”´»~“ÌÒd-#vž_”˜ý N#ÄÌp“ÇŽx®­ñZ[¡9D/ 8ˆAP¼t)SòØK/C bdSŠK‡^ºðÖRÇ/ÏnˆØK‡÷¦}’ƒ>–æûó…`G,ó™3gÑVoBø×HòØKOPB˜v¤$¯°0;Áê´PƒDÐK˜¦LׂFêòƒéÝhã·áØ*ài©ª°f«}~j8vÄÒKÌ‹}qZXQPÊ‚ý×94v ¼CÃŽ±\\ˆñJµ²°”•˜vÇûgމAƒŠ®)¬`•‚aïð¨h]"á_#áØJèBÃ.' T§¯"¢¯³Ó½ãƒN¢,QµÉ«‚\\ˆÙGH5«èÝGäØšcCé æÔ76ä7C _R 9èȥɱ¡¬&Ç+üáØK›Œ.ÿÉ‘NiSæ[àáØuŸÎH·ÿ´:/3WnÀ 0¸# e› ÑÕºª|%o< ð­ƒ $Š;"PFLźvÛ’ÛC]×TÔ1Gá­Áv•‡Ã;úP¿þ¨|J°#P¹ª>D¤º¡Ìä˜ìD CAe/«ô6FápìÔÈv^‰L0îÍ 'dn³C°#–† ù‘(¨¤¹j•a»Ã±#–Vãñž†Òšjß4…cG F®öÞš7Ñ6(&^a}8¼$Æ—]î À…@K¬¯jäå)½Ü}ËD6û-%Øp¼ØuÃÏ"!ïÚ¸3ÜÓn‚Õb\èœìˆ.©1ffd¢d…É1 ;bi$ tŽß­‚ÂÙàsȓǎXÚ²¼!Ö>³†tÉ¥-/©a‚ËñÙm³[{ñ“ó¯›>¶2XOºÐ1Qa °#°,?9÷šsÑ5X«§|S‚î}ùÂ[³ ¦2Ù´bÍÓB™@áÈ a‰²32Q†·Øîýðì«ý>4' Öw>mœ=†cG,.Äå¨p ü¶oæÈV™_úåÝÏ0ÇKKàB4¾$ã——ÔHŽ_ÞõŒaeR‚±´ÌÜ9˜ãWw?gp ÇŽX:™–ôf™àÖJŠf«×伨x¡_Øù´±yÇŽGšA;¯ÉïoßoØ ³í*•©©)©Ü,^¶§m™;’‘ž®ožõh»bG`µáKÄ]Ž–‹À¨-©\)]ÛP›*Øô´´Õå‰÷¯`Û»fæ ìHNfö겕FüeÙ°#–ö÷hd`GàaúÃ+ˆ±ôv՛ЭJ‹¥ÁÏáæøâ"Úo[¶ÉLKÏÂM5€hNö̬Œ¥£´1‚”žeà*R‚±‚²0Ä4Ç47›ƒ¥#w|&,s¯°‘ޱDÒ ãþ’vä®”zìˆñÏ•˜H›Ë$2h!›ÒÔUuWìUµ¸h{2ÞÄÅËÅCÙN«– HATP)>úìU%à 2ãˆ$}„WZP xd,–™–8b)ÁŽPãüÅåˆb™êª³6¨ÔxÜ9¶S¦%]] åŸî”`G,=×pgGGP1¤qè;bi™Ç8PãmGËgúG ¢55?ÍF}ô×fÝØêãÄìOBÿdfJE8v„hrv î‹kÔpÁ?ðk€»bG,=‰h*Šaÿ8ª(vÄÒÇÇ㪎ØcØ1G~É¿+vÄÒšdXßõC_1\EÙùó˜ìqÄ8(Ž6J¦cTýµÏNNÌ$®„t•åê Jþ%£L2ÒÒ°fý¸ë°#–·Ã/dÛW óºûæ]±#Tþ½{R`C Vä—ú•!¹&ÛFú’³Ö=`G,”Ãg˜ÁŠ z`rd|fŠr`€–F™¯Ð$(ÆbŸ‘–2~L˜u7숥'š:'îö‚êï#¦fpjTÝöEѬôŒJ³aÂö#ƲJ Z Õ¤Eb*šGµ(· ªÀ\Ýtç+ˆDÚÏCêȪË;U¿2¼+vÄÒ˜îÑ>Æ'é|6åyA&&;biÃÑ;>ÀÇè¤ +}}Ä b³êF:!JVýµaF„@U+Š* — ;G{p»¾Ãeìx‰Â±#D½ãƒ˜#RÑ`T”SPããuŠ á˜kj¡ Á±"(’숥õsçhß¨àˆªü"m¥;b)ˆÌL÷hŸ„Õ …hÔ±#–öpºÆúå¨bvêK wÅŽXz‚ð?V&hR}ißɼ+vÄÒK£u°ƒ8*“pìõñöP7í4 "Qê71ÒÛ*7O‚ccY­¿¶Ž‘^˜*6 Ð$(fø °>7ûÛÙû‚–XQ\Q4Ý)ÁŽXZ/µvò‰8Âjû§j°}¸‡UtqNþêŠ:ÿÒÆÈ÷Ž‘ŸKÇzl(«ñûBwÅŽhŽ#7:x¸ ÃKkK1\¨ ’³ r˜c¨¸ߨB’1ì™@6UÖ*“pìqlìê ?°žÆ SÄñF;ÛP¬}T¨L±#Äñzß!yÑêœÒ«}p¼Üs‹×,8®«lð{˜Äö‘Þ׆¢I›V4ù'(UØ*EÁY ZÍUæu®ñ…‹Ý7ûÝÛëàK4–Öøa‚hUKoßhS˜‘\ÚáØKƒ[z[{]‡Î¦»ÑÇQÝë4p‡¡!¨ŠÂÏñJOk§{3seI5DÂoµP숥]hTÉ!«é«/©Þì½¾„è®ØK aKßmåÈiÝs†ªüÛ´»bG,½×;Û~•5!,û–ÚµAK;;B}¼ÐuArh”j g•ìq<Ý~™#86U4ø•‰µ¼ØKGU¡LX/çÂÔú )ÁŽX:ªúaGË”ëVa¬vÖ(óWÛ;I p¼¥f­¡¥;biŸðb×VÁŠ×HÑd9ïø^¡Ý½­½—­µë·¢)ÁŽÇcmçÙO(U™ê7ú]_%¨=­lµÑ¤ƒk¶çûèã©;—e‚>BÀq!)ÁŽG¬ëÄBËÎÝôÿ³÷æÿq]Çèín ± nIwŠ4Ií²/Š,;ŽçÅIÞ8Ég&3¿¼ù¼?"ïó~J>ïM’ÏŒcÏ‹eK–"kßIQ”¸ïûÄJìûÒý¾çÔ½ÕuÏ] P°nY–ºoœ:kUSß[U³Æ»¤Ûî}Þr¶wØI…>î_»Ý+ɱlp~á{!XÚ÷¯ÚìõaÌ v„è³›g ÜuÔÀ4ADÃØ6N¾PÄã|Fƒ:FU¾’<;BtäæiØÔGűºaÇŠfïY{F숥 {c;*oïê­%ž³É|aGˆã±–sœË†¡|o‡h¾°#åuºs™/'WUÔ=Üt¿÷41#vÄÒ×ï]úŒMGh´k·ùâBæ;bé+ŽCöšcZƒ!(¼º‡0ùÄt`ívãR Æó;—Ž…fipɶºõ[—i^°#–> }|í„IÚyÿgïªû|µÕ¼`G4Ç¡¯€c+÷qïê-F¸JK"?½qšáû(fh+ ŽK(I`,Ôã«­fÄŽXZë¾qRr|dÝnKQè#Bx8Be@.±y ¶oÍÖF0Áf<Örm!Oo<à½çœ/ìˆâØrîó–óÌò †¨—ãŒØ]¦M*GhFˆ/¯~D“Ž«8Ø´l-¬/DZ#–q|ʘ†bK‹ËZ»Ó÷úe¡aG,}~rWÖ‹nNLX`Þûvè2X/Î!:VUT¾²¢Î{5#vÄÒ÷*·zö’`w4,©[RhZh8G´ tA.9À‹âåe5†ªÒ׉÷úFèî'¦òÂRß[ŽlbG,m™ôˆû^4¶œ¯ß!›ØKO7†”n˜c¢>zÃc ˜ãk‹’ÃÛ°éÔô¸S•¥oi’¹>>_é¥Ç¬xÜßK;_ØË}$¡²Ð˜­Jëûötš!2>GˆfÄŽXNô†â[ŒjáÚ¼e¾âô[cGæ4l*«£V¡ßrq•Ñÿ›¹Ø,ªš}«¬€uü8bùÂA¾$"ˆÏŒgÙÇy$òÑú¢g~oò7³f|ˆ{_pâ 4> 0~[Âp¥u:ó¹W…õ Hwþ~v,ïUÝ#X´¹‰ÜlîGpô5%¥tî°Ü™æ¦•öÍÇÊ™RÐÃÔ|­˜ÈA0;ÇTÊ×Þým -‡%êk¬»8:.‡ðb¨*7‘˜mÅ·½áÅF'Æ’¹yáÑGÔ6ãÊ™%GœÁògâ8­9æÏÄq–421ê ù„ՕЧˆðbãA8H¦INR©×*8êÐeó°$°gS³àˆXÞ‚zfäØ;28f¨¢ý¾€ã/‰èVËë12{¶ÄŒvÂlú8Kš GX/ãÃ^·¥A)žÑZÔD¹yѰpF'ÇJ=h¶/FÝÃ}¾‘/@ý£C°pæK ÍŽã ,´ù:XÍa‚ ¾|á _"Ç‘ª€Kv&C̨Cç‘fɱs°§¼°$›—ƒ÷|]Y’`÷BkÏ(0!TsÕ+4ÙÕž‘°›q¸Úî᳙赢Eô<Á/fÔ¡=Ãý(3/æñ,9Ά`´ãàûšÐ—Dšã°/`wQp¼Ûßé ùòèN_'G] "X/0¶}AÉ’º‡zKü!yÔ5ÔëzùË£Û}PUáéM3_TŸ$CÌ‹eލÍûšÍãØÚÛô’€ä&ÈQýeØé|qlém ‚0a¸ÀqÆQ%µõwy_–X,4«óKjºÃûûh`l¸(à•i¦éÔ4ÔqÐ{ÂLŒ†œ—†Í#ÍÆS}"ØÄŒ·vÓ©”o(O±é«¢tYv[³Àgd*Qýî±#EQDEQDEQDEQDEQDEQDEQDEQDý®(ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}u)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}ué bGÒV:fÅæÎ>íü+¤¶´•iaX1Õ»U±˜±´.çÔPÈ© ÿ‹i á˜iXG]HWX[JTæ˜J§lvÁUÙŸ©ª)vq0ŒûBM)õO*¦JàŸxPUT’ÊqœN¥øs"î_•®'5 Ž–ª*¨˜æhŽÌ!å☨Jñ¤Ï±™úèpôï# L§3s9¦¦ñ?{¸A}œJMcÄP' $Ô$ù#ŽSÓSh:ÄõL§ñ¯ªI„pœžBm`‰zÂ8¦¦3}LäpœžR}L¡]›Ã&§§2U¡i£:åpD >Nǔ昊ÙpTµˆ%‘‹…ŒêÄô$ÎKäú–¡ ¢ÏqÅÑT1Aèe:…aÏE/ý8bút±Ib‡’¾ò4‰¦§r☠œÜ€yD^öAU#ŠMLM(Ž9y¹Áy1GAÇu=D¹‰Ü`Ž“(Iõ$sò‚q˜žžN$y±€ÁwsÌñ]öó ±rò8‚–}Y„c“ªd:…zò0“~1VS“(†_Ñøüܤ?Ç©I^„˜ `Žã£“ãøP› á8åôQ1Íñ.pĈ¡0 $õó–A“Ƨ&G'Ç4ÇüdÇé©q= Å.¯  ãªöÊ Z«šãÄÈ„êca^K—#–ŠáZ6A+gdb eP'• âˆy䯅yù¾U#ËlØŽü9™›—ðk<„óø,8¢UãSãX®yªÉüÜ Ž£ô!­ÖsÒW˜@.Mó×¢¼‚Žã¬ø s‚¶ö°ÃÑ æˆö£BüŠ2EÉ@ŽXÏ( vX6A»cx|thbŠó Q&˜ãøè„昛,NúVv¬ø°ò}%9† k~h\sLbåûsT[íƒZ,ã8Æ&ØùîG4‰ö5QPUšãÖvvæ[lp|dtL§ òò sóƒ8ŽLŽ Ž©>–äª>úÈpÆÎÅÞ» µ:86<¢º9]˜W@‚Ÿ£Ø%ùE¾U¡ –4qDmAÀq‚8ªVùîGü:,8–pÔ’ÄVî`´µƆø3æ+¢Q8ŽŒBUåå—æûV…Ä‹0D|cÿ¨bZZP\Âq|âW´ª¬ #ŠMM@U¡Œ/Gè”éÄç²üìY_ŽcÄq|$GõKü9ŽN¥l™ÄÖècÿè ªJIG|¡IA»–-°ó&(€b}#Šiya ªòïãäxßè þM’d6ƒªRÕ.³Í‰òÂÒ€>޳€à âØ;2ÀŸ±ƒ‚8¢¶$Õ³$€#¤ÄÐØð¨î#$@IÒw¨ªÆ‡§¦§KtU¾v €A--‰9Ž g&(7d'ôŒô÷«n.)*-Mq¦Ï0¡ƒ„ 8¢„!$áÒÂ2_ŽPë(¦øŒ2¨ÊWñAðŽN8‹0‘$L —Øú*Ñ÷†ûùsEQ™o-ê3K"˜ã[&„¾Qň)ØA.ùö•Œ=‡£¿0‘ƒª"Žüµ¢¨Ü·*%íDzŽÝC}üâ+ˆ#IK¢Êâ`ŽŽ¢_º‡zQê»Êâ%Á3â Å|«B™¾Ñ!0»ò‚â )×¥8¢NÔS^P0A£¨ ¢ 6!ê© àØ§8G” ²÷À‘?qV!0Á³ªxi Ç‘AF=(ıs°‡?W—øWEªŠ>Ãt)®¾‘>ÊAUùr„MˆVS°CÃ|í=p„”C……q%Aâ õô*¦“(°¤ ÔצůRD×”Tø÷Ñ1h-mqì¼ÇŸQÆ·ñ³äUeÛíi5\Aú¥c@p, æ8ls„V[Vêϱgd w¸|•**…hõ-Ö>Ð’°3QÏÒ¢2_ލez†ûórrPϲÒJŽÃý|K¢µÁ‘?£6_ó‡Æ3´4@Dƒã½‘~¨Ñ¥Eå«AÛÇڀƃݽá>ˆh˜ ËJ«‚” ´ ta¸PLKü8âWT•áXVå[Õ qêƒÊCmA"eP!™/•Eå¾Ã…ÝÃ}mý]Ä®.ˆãØðÝþ.˜06 Ÿƒ8¢ ˜Â²­T£Zî«ÜÇU{QíA±º²ê ŽƒŽ¦AvÂÝþNþ\Q´Ä÷ü2®ú˜˜Ë8Bq`(À¼Ð° ¥p§¯µ¡NÔƒ¡ð5È1¬øÐ¤ ªÀ’œ8BÚsìàÏ(ãËÖËàØPÚæ˜¤_ÀŽoÛ`øZ&(€b·5Óå5U‡ÀÔéã,9ùZ&ıµ·Ÿë—, ã8êpÌÍ Òh]C=|/Ý4AR£©oUàˆVÁœ€-vAŠe:‡zÆ''P ªd©¯-DQíA± Ž(ƒúdžP ŠqlÇÁ{¨³º¤¢ºx©ïá¿¶ô¨bÉ\p¬hæÈg4ƒÎ¡h9Meȹ–}n^e°\º§õ d ‰_ßbö¤F—•Ti4eä@[ÁÈÑöFÐpÁ<Ã$’‘ë+Èt²7lÛ“h¢ÃK0Ë#­slaºƒŽíúZU™¾Iuwh÷ÚwGéT¡: Ý¥ÆÄmUÐåž¾2´´'7®®ýopâP7Ã)uI vA—´tÛ–ˆÇ1ƒ·èÓ“`гjŽò^`‚Ý”ö¿ä*oBŽïÅW:Fm¨JyŽtm¾UaðÙ±äk³„KN± p;’'×ö™*oNˆÛ1EžèŽ|å踫ý]rÂ) rX§…ƒ\WXŒ¼¹Až\ËqÜÏèß·Z Q`ÃBêáÚæçð{I¿5v$íþoÈ‚Èð˜ame\ò¾ÅØ7–¦ååáè,>Ä$îïXM¥2 ~SŽc+%Úe)ß½§ Ò¥méû /;턞–ã›Pxÿ«vþì£MMf|{± Wè¤òJ²Tòñ_’çÕ˜w¯CqZ»–e!r(Ê–¥5; &°ôPø:¿¥ÀW±Ï›™¢ýIÅÑ 鬂£[…Ï©AwvÊÃ1=Í÷ÄÙ¸Ès)Ÿ`¸òs’r`j0Vruá×üÜêÉ3ä­­Û¹öJ‡^{ñZE K¨ÞÑÉ)ç*¯ Ț͵Wæ‚&àJ}„õI}ä+É/4n¾0V}£H«¼ Ôè&xñ¹‹H{†J¼b‡Îÿô¹Âïüsªw¤_Bßr /G‹Ž—ã|ØÃ¹=ðlÌŸ}ÏÆ´ÊÍQ] ûFíKÛšHã¨à뀡C#QÐaoÌuØK7,©õm|ÇÀ=^‡e~·½Ø³]ƒ½N”ÆnÅÀk-ï@´|}äó*,œpœ“jZ_¿šÄôu ÷Jý‚JjJ–zÍhu ªn´Õh%s“u¥æ=¤Ä½¡>¹ý--Œå ^C=𣣉ç,+­4.Vp êUt5éÛG, öL`¢½÷qó¶î)¡­ CëG×T¢wúÖ;c÷% —•VHŽècûÀ½!ÑGüZ]²Ä+v "n÷eVκêU–á4ËgBÌrСýbÇ þŒÕå+»À±¥·¿n¨Yí-ƒv‹›}KXß-í…öëôƒ±ri­ï:Å­ž»üuã²µ¾¿yï.‹/샤ܹ¶«üyUÅr/Gˆˆ;}ö²×s„2 Kk%­m  'vi™€£q÷ ¡µ¯CžTQÉÊ%u†”Æš¿;Ð9=Ùh(°jér/æãZw+{&ªK*¼ßг­½mÒä€$G7 U‹ ’"ÎÒ‚3îåxµ«…×!¶ïÅ7 \éjá¯ÛWlð–à¢ë?1È¥UjT36 TÿÍž6éвԪ¨3®0`]î¼)õ ì¥UKëŒåz·¿‹®ƒ™–•7,©18^íje`ic»Ã{ã386|±ó¦åt`÷ÊMÞ>bHå5®¥uÇêŠò 8^è¸!­Pp\S±Ü«m±/êÝA#¶gÕ}^Ž Û}<•ËË«W”×øûôæiþ¼qÙ¯$é¸ÖÕ*­/ŒçÆÚµ^Óý\Û5¶…ÀÎ+L° Qþ-Lè8…qŸˆ%qãÞÉ­Ú°lµäU…2ÒzÁx€£¡ûÀëJç-ÞþP˨侺&c£u ö ˜¬ K«©z•·§ï^fW.xA4Y~ôñµã΂N?иӷ d×­[`bÍo]¾Î·Ø©;à8HZkëÙ(€]vêö%iã4±¾f•q¦€¼iKK»eسU Þ>ž¼}±ÏÙkÛVlðµ0ûFOܾÈU=²î~߯cŽð}F=;ê›}‹½wù3®jûŠf\:ßvÍè#F̰.wÞÒöRæÐѰd™¡û Oß¹”±ô’ØT»¶Ê£ ~¶œã¯_ßð5߯£ »9×T®X[Yo€ˆ8ÛvmP`Àq[ý¯ß±g¤ÿó[6Ç¥…¥»Wn6 ÀЏÐqón‡|Ž˜Gù"âÌÝ+ƒÂŠG ¾×8¿êˆh´çþaräæ‚¡€À«ÉÍŽé7ç>æÏߨô€ol4V hÏÞU[|‹}zó#QšªV®«^i€¨9|ã´4«pFÛ¶b½W‚A)\vv7¬Ù¯­ÞêËñ“§”-¤«Û·f«¯ >¹~’¿~û¾‡}«ºÔqó)Íqÿšm¾Å~}ú}þ¼Ív_\,´C×Oð×?ØòˆoU°ÐØHƒDõZ_Ð,GnžfÙ•Ö“õÍ^,,4%¾úÎÖǼìNß¹|µ»U>i®Yݼl|©u´å¼ÔÚà¸wõVÑ1'ßš@Ì‘<1á×Sw.¡dƬJ+m5ämÛ‹'ÞæÏ5íòúí !â$Ǻ²êûWn68~vë¬ÒÚâJ«Ë»Aÿëø›üùû;žôm» ýètpé£ëvûƒ$ìr”Ú¦ÚÆÍuFˆšƒ×NH 3ä*lCfbùh½À-­®X oipÐûøêq©C1(!f0í¼÷î¥#üõOv}÷ñ9ø‡>Ãè}|ý^ßbÿúùküùñ {}q!àøöÅOùëŸîþ¦oUX‡ÐÈêSÚÚ²|Ý–ú??ûwçcú‰ û|O8¿uñ»eýÙýßö–ù¼åœ:˜¤¹”…5oHi¨ã÷/Ö#€/óGÖí6,d˜—Ÿß:뜵UU5¥•®»ßëÎyãü!Æ…`nó³¢Aÿòé¯ù¾úé| r¨ì“Jk+B3 à\ Q¯åsf«aua)zkû‡_âÏùµïx àHõéÍ3²ª•KjlÜ%/jÀñëGÙ"Ú»zËfGí¯ûˆ¿þ‡}ßõrÄ.;|ã”úäðĆ…0ñ^ ýûÙQ!•úÖæ‡¼¸Þºð‰|· 6áÃM» ½í¬å¼|{ßèãÉC~Ý·zŒ47ÇN“—!àõTó~/4F[&»6ù:@ÿïÇ/ðg(_$ÊþN©†þãä-sðÚql4úL#ÓëÀÚ² Œ hyg‚>~cã8z˜û:_:ý.}^^VíÕ/ãSKòÎùìkœüý‡?ãÏÏm}l¹ß1Kú³[gèNíùî¶Ç½e@¿<ù6Ÿ˜°æ÷x,X¡¯žýPšU˜šoo~È«b>½qúˆs°B“¾·ý뾡ªn;ØBXöŽ=¯œù@^‡ÂÈy澇½Ð,{0¥Ï8|ýáŽ'|9BU1Ç?Üþ„ï…Lè_œxËræúÿxôϼe`ÙÍ!˜Ð8ÈK-Ìã˧ßkíÍ«ø’ÐØÚ`‡böͤf SüÙ-@ hFc£ílØø¨ûÜóæåÓïvŽ0D {ò kU¾ém…uè…†üìèoøÚµÛýcC¿>õ~×poŒ¼1u ³Ð{ÜÆÒB7- :À"üƒ-°ñ1¤°TÉÛB^è+6lwš`‡ºvB8t9°ÌÍÉ\2Ôèõ{wN´žŸ"¯.‰5ƒöFÎieVµ9Õÿp:öa,%0?âB¾¶=êÁž•Îóê⥛êÖzÝm'Z/Ò»(Šóìª óH;<>z¾ýúÄ4Mª ó¸aÙjãRjQ5žK£Çpâ3nr®uߦ«*jWN<¾¼¬Æ{½qï6}F½¦ÝaRU…yùÞËöT:u·¯kTû˜hâ±DU± ›ÇB%÷±.SxÁârÃÐ/9Œ°ç|qò5Žäè#VŤžk*‹ÇÊ J \ ¶–«Âg8.Kœ Ë J¼—{ _žš¢B¾ïV.9ŠbP˜›o¸9°Àô•# U¦¦0×íO´Ò„zá'jI'üݦ|?† ‚ÞÀDUú¢@õ2‹ác2/Çüßôê» *€ö'†Ã—âX–%ç(è_ÙǨMZVeà¸å²Bo±¯2Í;b×â‡çÈüúebGµd4Éò 51#vĹ;“íRÿMxà#3bGd™9¾¾»(kØ4i\xõ$IøIo!bpÛ.r»fºOx›ŽqÀ†º‘â9šä}ëk‘bGÆô«ÒÞ?Dm¬³1AÐd¾»² /ÉbÃ5"n7¾/V’,äyôGˆä[˜ — ž·Ê {Fìˆz.5ey(™Èó¢+æ;Ò/ÞfÓý±ÿ‹eãå¸H±#÷†ûY÷‹yJË·d°’ùöÙ œ¹§˜ y/ÆU¡€ÏŽw¿§ÂUA:ÁŒ6öȼ`G°žý8*yX]RÁ².±2ØÍ7Ï;YÃŽ@¢¶õw¥\ÍþŒáb‘ˆµ‡­å‘ÑØÔ+Ê« ŽGŒ§¯ˆ®-­4ÜB3bGp$–zŠ =åë¬ÒÛ}Žpvõ ®¬š%¹zEXÜýqY,0ïa;;‚ŸxÍ#†CÏ&v³;d 3µ$„{'%_é}¿jbG°ü|%j[éqˆ.4ìäƒìÏ”2Æ–O_7ºo/c®+‹ÊÙI%{µ«EB˜ÖT¬`AÝ1xÏ~AÓ]$pSõJ㼎GTÁ´¶²žE4vk»xA“ ûÂ¸å´æ ;Ã×â²—°sš—eÖÏ…ö¼Å$AJð¨Bz_v¹ÿm‚A‹…ÁªA½åجK´»¾ÂR:}÷Š9&ªSoº.CgÄŽ´ô´Ém™Jò‹x€×É;—}96U5 7›Ø‘ž‘Ë7½…å·½¾Ù°Þñ#\§œ>J#ÿß´¬‘¯í0ARå Ž‰ ™ãÙ»Wû…3ž«Â1(Oܾ(G••Û}uMÌÔbrTå ¶{° ;xêö%ï_åèábzµ«õvæÍÌðC){}Q ;Ò5ÔË® £û×nç%q¼õ‚£µ3ØKŸvÖo¤Ï0þ^;!Æ\ãoÀGæ;›ððSŠ£ç³kå&>2#väó[gµWÒ¬ ƒ… 82úèÐý+7öÉ"ÅŽÀhaO‰‹œD΃kwöI„Á ô­ ŸÈs(ÚÞU÷ð‘±#];n €‰+ëÙyãÿ»—ޏN¾A²³ kï”ßÖÆqïéøTøÑÕ£MDbG,­·®Xoüm8vJê|û5/GH'¹Áß¾xØ–î+Ŧꯓ5ìL-*MÊM$žÚx€MVHÂËÎò=P}d¸lÂ7Îò=ko®k‚~”"ìèÍ Ÿ¸ rû?>‹÷Õ3ú^£AEòÛíçÛ¯C’‹íªr¹ßÛþuÃÛ‘MìÈ˧ßïvΡ‚6Õ®õºÒñ#X„'l^.s2_Š”—N½+£U1ÁT0¬…±#гgù'xâtüœ.޹Ûß…ÞVaj¾»ýqf•qËÏs7 ‰úŒ£&¦&ÿõèkÞ« üÑ#M»ùÐ3éÍ ‡|8æäþá¶' ¿c6±#/ŸzOß¹¯>‚CпÃ÷úåéMÖ¸Qò3bG°$Œˆ¶,_ÿ`ããaÖ°#8výìèkã~}D…Æñj^°#ø‰0^úß¿ö㤖MìÈû—?;î%­XRóG;ž¢Ï8|ýÓ¡_úÞV=²n7ä0Qa“#Â’9y?Üó ŸÑ¼À¢ú%5Ïï|š9þãÁ_àß^WÖ›¬0>±À˜S2'÷oø¾q¿ŽÁ ô§G^U1­‡å0øö}±#¯žý°½_Éy‰‰i3€Ïø¬_øWŽ˜ë…5)´0$aŒ]ŸŽ³(YøÄ†¯±YõÎ¥#ÚÈ‘ØK_ €5vóx­û¶l6•-É/ô*ŽpìN»ÚŠ`ǬS[,ýÎFÎÍž»NLbGðïÂdþ&qUËïheÖïÎj^°#©têz÷•+@ðrp-å|廫SÙNmžêšˆ´õØ]¡ŒRétç`·¾·õGœ|ÙŠ}Á‡z餎Çc…å†<;‚>BúúÐåÝÚ 8&˜Ùÿ[±¢dÿ‰ `,›—›“ã…}d ;’¶ÒSÓæ :fÎ$.{àÃ/ â¸mùú&½Ì`g\ûæi!ýÍͳ†Á¯^ä+µ êøíÊ…­ûê™\¿‰Ï{VmYS±Ü"÷Ò]_ËD½§ñÌ–Gä{„i¿z/ŸhÞG:ôеF<¦âdÁw·)òÄôä/O¼ã¾ ÉÔˆEh C²†Xþø*omS[aa·”!ØXþ/zOFU‘µ>ظ“6tÁGWùž ±üžßù”¼Ò ÇŽÀøÿ·c¯Œ˜  ŽyUÿê×.Èäá¦ÝšãðÏŽ¾î=°A5PÞÀ$Ü@ôIO±)‚.'×W¯2쫬aG`HüZºöÝãúì–G)¬„ƒ&„ c+…cGÔ¯§Þõ­ ¬¸çãú%kØ‘ů¡Îïms¡Cæ;ò≷ZN¾ ²Ý…ÉvG¼>ôKßÊ--%¨N˜IŸ¸“0átöWû¿Kg´:ô¢L(/Cq´‡r§öüÛ±7¦Ÿßù4q„™D¶™w;âTû7þ>ÿ·ƒ¿°9šåÒ°Áö»áØX/Ð錃<€¥Å¹÷YY8;B`5™óB€0bßßñÉރ׎ |Ô”T~}ƒR¸º¯œþ€|ÿvÿ…MµIGkÃñóhËy~n‰ªðvŒ[¾ì ª®¥»#;‚ÿmZ¶Ö@'‡cG ÐµCÁ;‚y¤ÆÓk!± n„‹©g«+–S€Xbv ‹}²;’ˆ'0Òÿ2/ØJ9Ä͑ؑx<¾ri-]Ò¶ô´M§§½ØK¿ÅDG±É‰Î¡{.DˆN406#GT8vD¤³JƒON<I‘ΰ6³Re;â±û¤kHËs>%ñrDƒžëX D#NœèIúÐÒþÔ´“*ˆMˆT8‰XÂð4‡`GÐý)çnZçgI:O,zRèvi/FìÈèä5þ¼ 7IùáèI\EÊ*2‚Ž`0ªÃNbz‚ƒ<*áð€^Œ Xcá™#fc841ÂÞ# =¢Ž£C¼aÐ5<—m(Ê+ÃŽ‘AG Qð·ãÃöÊI«'Åù®Y˜;v¤gd€åê‡Y­Ì+ce¼O°±#ÝýœU„5€^óÖÃB*+(1‚ŽÀ6ÂDÈ4Þz¤tpÄÙøº¤ Då)t‚žaYV»C5†`G°eØXXZ:cÎ Ëóš’ ¹M採ôÒüuYi%ÚÐ'"6ã V/ÚÌŸ§{¨cyCd;B!@ø«Ì”çÕ‹'Ø¥^g1z葌¡â =‚GÙ5LxIl¦LJÅpìlqÞVÊø..DZמT•,Å×Û";F]YÄEçPfýSè‘îá>޳Ï©_Rƒ â8¥1Ò¬C°#2舥}ŸPp2…Á‘7'ÿ®Á^–*P¸«õmïÕ®V1* uko‡|"½ ;r»·CKf5ö%É¢šÒŠÛ½í¬¼¡GvCĹ½sõt`»±Ë–CpÐKk½åˮ߻Í^OhôÊñ’䀮AåIlf6t"7®Üíïdñ¢3}¬‘çÞì¤| ume=Ú ·…Q tîÑÖ€__³ K·'³ÙãÆ›(sÇŽ`îØµ橺ãÀAsŠm{êÎ%¶ jK+Ë K.wÞ’Oj˪Œ #ÍËÖÀ±ñXiû ÖV¯vÈÌòÕîV”L;·Ô5AG°#°\/©¨-ö#ôH8vÝïsf ÒûãÆê›BAG°¿°T.tÜpž(y.‡7kجù[÷ìý1µ±v v±#¢ÓqCð!Øèù¦VהΠė…U ؘ2è8n]±þ¦HLáG޶œgEyÛTÕpöîÕá {5¢ž¦ª•؉ì&±ÔEdþD. ="ƒŽ€ãöú ×»ow:[¼öº=Í ;¢‚ŽÜ¹Ä'] vœ/x‚­ éÍñ„ …7Ô¬:Ûv•7o~NžÑÇ…iëï:ïèLV;„j[7Ø¿flNtB¾|cíÚc-çù,@¡GT@á†_W½ÏÝ:Ï–þJúæŽÇŒ>Æ`Âî•.ÛÍuR˜„cG>ºzÌ1ÓXä÷Õ6}Ör–-Ôƒ% á Á XÏSÓÓ0g„YŒØtÄRq,vô«àЃ;¤ûŠcG nÞºð Å"©,^‚eɧïõÍ2¸]8v?±•Í»«~ãG׎±H„:ÆðŽLŒ¾q>ó=Ä 8ì@M+çFˆ2ìk6ó _¿W'¦±Ebn"ñôÆ`n½~þc֘฻aóWö;Öê1tnvD)Ì+xbÃ× ë· ^ÏjÎkç>æ°©Xê°>¸ü¹ƒ¶I¯ª¨»¥k›d;by²y¤ô˜ÖOöC ¹yšE.¤ÄžU[ 7XžÃ¬¥ˆ%^Ë(éĉQU¡G"ìH&èlÂòeû×n{óü!û0u ¡Ruò¾2Â9åæÅo¬ª—AGŠ“!ŸÝ~gËc°3¯tÝ"é ›ävªø/{ÙUŒcÎkg?bŽx"½éáØ‘¯B¾ìëö½}áÖ àøÇ»ž–åC°#Ð\9Ê_¿»íqˆ}ùUáPðþ•Ï5GešA.=Ò´ûMÅ1s¾ø“Ýß4‚Žì[³ Œ^9óž¤'8t@_ 66~°ë›0*.‰SžÈ«Â¬aGdÐ{]¿O81 ž@ËÃùég¯òŸ<¶~¥Õ÷O¤> ÇŽüäÈ+lÒ¬®\ñøú=/zJÐÒ£Ó\³úñ .©’ìTÞÏŽþ†¿BâÉÛó#ôÈܱ#xþ≷X˜@võJ=Ž'2sMÖ°#ohÀ„ÍhI dÈ˧Þç·`wýhÿw #¬Û ™ùÂñ7åäЉ¨kþÑþï»{ö÷ú¯ög´—N½Ç6*ŒÏol:ðoÇÞpN…*Qéó;Ÿ†òO‡~Aeðçª Oµ??ö:süÆÆPjgï^ùÃ1™Èûó½ùìäŠí_ø¾|5;ŽÿüÉ‹F öTó~œ¤Þ¼xhBߺÇb ~±Qdñ ÇŽ€ÑJM¢*ƒñPã.Ⱥž‘ò¢7U7<°v ¼xòmL(ý2=yøú)†ÀôÂÄF…êrÅy…OnÜwüöE:ÈÇ”cÎ6r´Y5Nž¼•uÍ5kTNC}~ÇŸbTÃZvµ”ÐpŠÜ$šÙu·¿‹°#¹I ,‚ÁQ÷ôÝ+ x²¥Ù'G-…¹ÖÕªó©'EyùP8Åë›õ,©nr”%e7NQ1º;‚VJÙwG±e¥RKÎ;BAGRŠ£j.,Oô]¿l™¦¡«,R¡GèEGÆ–`¨amö 8ó¨$Žº(£/–íQ-/,_á ¼Ž`A€}ÕOì^ç¨ì3ê’TF"¡ì6ƒ÷X8à+Žß^}RµV-‘c‚ÁzcgªÊ#¨9v öL;à!þåÊ™;v†>ïŽ)“š{„™B§¤Ÿ#Y¤Œ*‰üPç )ù³ƒÁ|Él;äÃWv(æv*ûû‹’…4ª"f†Êp)…gv»†ovÐ_âØ¦ÊÛRc%¯}C°#ØõòeâÚ²*H˜¿Ü#Ôó j ýHŠƒ8b‚Xc@У־v^TôõóvZOÌS‚éÉd¢QK‚ê·E$”Ç–¹Ñs—S>--,ÅJÆ4µˆ·6–Ö–®XŽ@ w®_:2väB;Õ ¦¯®¬ ;¢™ò2ó‹µÀ°#7îÝá°Œé’Hºt /ˆXèx]€E.ûx_]¤¿Ð†þR›¯ Ð dêWXç dÝlÊÄ k*WH›!;¢@! CIä6ëë ”g ´¼¬úrçMulsF ‹‡%étl¬ª—çŽÁ€óF[¦! ØGÎ:QÔ¼lõT*uEøû7×6B˜·©·IìËtÊnƒ¥ÎIŽñ„®lη_WSw©V>ªÔU‚sRÅRÇJ€Ùs¹ókyLÐÄÔ„¼´E›aMÉH$P2ƒO8vDF&WoÃ/QåÅnÚQß Õ#Gig}38bû·Û³–†žj®É\Be ;r^aAlˆ%±¶J9Å J¥Õ02éFv¤m ë¦CAïî×Nñ³ª¼sѨ! \C­Ê>£0sÒY»©¶1?7ï¨xKº ³Ã÷>¨ïª-E†B¡°žÙ͉õ€Mt¢õ"o4z+ôSñœ†˜då‚ÂŽ\ín½¥àøc(v˱–ó¼1Wê‹9™¥»SM*5.™!nAaG ôØWEHÞAéÈÄ¢ÅRñ>®?ÖšY'¯ß{WÁP®É'–^´,Q¿L1wìæ—…IN,þ¨v«@&pùº²jyG‚ÍðÑÕcη4~ÂÖ»ÓßyÖÑ0i[¿WcAìßa¥<Ô´ >»y–í, ™l1bG —xQá\Fû ƒÃ …eù¯8v’ðxK·÷ìVå98Öz-ÌÚ²J9 !ØÇþý쇬.ñW™ØV%’N?·íq¬(¶U`¦Ò(a‚º¼3›ÈxÂ[›žXÊ÷ŽS}úÁÆ]Eyù¯ ÷ž`“âÄqÔÙ&¨ß“ìH&ö…C¸¡G2fþÃM»r¹Ò)ˆ]Á)á8ÌÒ…yßÚü ä˜ìˆÎDc/c4é©û- ,àcÑfU¾é—'3 íõÍë«WáløîåŒx|澇a+J‰'EÉ'‰ª êø1üøŠcG&¦'å‹ï4í†mëâ}åù³=Ï\Р†_Xá ‡:à&þêÑu÷Ë'PäüÉ‘_[Ž |ªy¿4§³ƒÁYõe!ŽžÝò„3Ltœ¤zô§÷KÖ‚yáø›l„À„†ÞÇ׎¿Á7EÏn} –6é z9ƒ³09ƒŒaÒ<¿ó)®3;ò“#¯ðm$<ödõ¯Nf"X<·í1)ÒC°#Ø E0$¾½ù!Ëqîrý0 ÿñЋú›2Íö­Ù†'„2ä¶ Úð¦ð÷ÿÅÞgq~Á6á7X°û°$´y¬žá쉠†÷Ó—$脼¡DÙÁŽŒOMþ÷O~ņÙÓ›¬®XqýÞí×ÏeòzðùSw.Á¤¯èÝô¼`fYGÄ$Ã1; þÓ#¯ð×ï(,H5¶ jÇ~èeû³ƒ‚ã€ã…”xÑ]^êйcGpS>ÿénµõþ¿Ïÿ5&ÊKK&kØ‘øðç|‹ø°†€ ¼Ô€?Úÿ]‘^O0e8‚½'2ÝÔëì6мl|¢%”ïæï?øß1BZâPó½ó/\ÕÓ Ò("‘¨6þ—‡«’í<ú?ÿ K/BNb…úÿxçÓ/z—ϦʆïlSkïïÞþ1Wõô¦$h2;‚sÖûW>#m27ù·>‡¯œùà:ʼnÅp ÑA‚þ¹Ž™DÞCX;*&ӵ㌢€è€ÝûYËY*“Lä>¯õËÛw QêÅKâKŸv öR]Ðþ°`P,ò6>Ü´VÓ»—>egócë÷àz­«õLÛª  >;òá•£cSãäzm¬¬_[UÓÊAÕx;”É'î#Qvä–z—£z]œ, eG×ÔxºXø¼åÜtjš†bEy5¶˜áÕæ¸qÙZPb܉¦bß©W¤H™Æ ó’ò^tîØ}éÚa9aPÖV®ˆÇâúx€†Ž‚[ÃÀ!ÐÎݵZS·ô´§,;pË’Â2œk”}î  ÉS ß®DUС*̉Ñ:=‹Á $ÐỈéÞ;2¨3+©B؉t¢'—5£$Y”Ÿ›ñ,„`GІá‰Qvs³KNºüÐTX˜öC mÈ!Ç%иÚD"Ž1g_2½‹Žzl­§0.~³ƒ™N¥R™-vN;í¬.òΣûLÙ_/üûÚ»ïöïóg;â:x±#!EIJQè¬iÂçŽMNð¨ê¨bEÃã#I·ÒCâ!† ËCVNj ìHq^!Ö$3mw?AmƸñà‡D!Ø#a ”%¿µ¦íÉ¡›#vÄHXSQX†ñQ3ñ6Ò8Íʶè°#v=g˜èR¦¿~)ß~ ƒFÂD8C|ˆu‚jÛ„Ö& mí&L;]‘ìˆLX£3Ô”8'ÄC e˜+vVo¬Z ÆCì_v‚âÎaIðÝåˆd;‚Iäe‰íIó¨Ї•h ë»2'CM‹xh¤­ ÁŽÀäåôïC¢ì‚ 0‹”ïCJXcé*´_E-äµM–½ î]]¼”F×LZÏ‚”9!Ø™°•Ó½Æm÷Cœ…¤çx…¦(!/]æ(£FâØ@®#‹ô—,(ìV¸ãÐ"¨ÊP£³ØÜæ2FÚš…AcX¡cIP ê¡DÀ”—Ýi¬jÀÆ êºx¸¾f¦Œ·*þ„Ö*d‚ñо×TSlg¨‘Ø#mMv{–Ý~œ¡Ff±¡‡À€äìòòjò¸œ¼y™ÛH[3wìÈ ˆ¢©z%™@ÇÝ!Ãå“ïÙÈbƒ‡2a ä õÑ~¨»DikdìhlÚÚxÈJg}õJh™°†ZF™!;‚=+§Œ2ÔYlÖ׬F œ°F…ÖÐ}YlÒÐG2mMÖ°#'Z/²¾ÀŸ¯X¢jøüÖ9J“öDB°#X„5986L³˜ˆçÔhcO†TÖXÌyw·{¸–¶ƒÆ «64l*5MÍ;yá‚ÃÀÒò›Ûèã½(cÀÀØ0#3òsòHbŽ@YRµXá(929Îޯ¼‚xL%Ó°]ú#mM¶°#™„5ìX§H öÔê˜"Sî0äÿbØ#?Îl°#™,6vľ8vÄ’cúÀŽXa‘0ìHN"m6°#9q@$;بœË`G8Cå‡ÉÓYl,7vubciØ;ĈĎ`x¥„ZtØ#ÄaG,@>”ØL±£62ØKßÈψI*ìHŽ &¢±#–vWgº±#¬¨$vÄrDf)ËW0;RâˆÌ/v„‚4Ø‘27@dÑaGìŸÜØ¡f ;B0Ë!@Ɍؑòü.h–Ø‘’d!­‰ÉsD²€Á*ÊË7Ò²P !‘‚ÁîÃXúq;Ò.‚‘Ì;"CŒ0LĈ¸Í;‚ã4fŸ8JìHÏH?;~¼ØÊbc¹±#K KÝ‘/;‚u…®ˉ0Î]>$ZPØüäxI3ØKD¬…‘¾jÆŽÜèÎ#ñbGèÐk`GÖT¬è¼Ç•ìˆ 1ÂØŒÄ‹á#;bDøÌv[FK›ÀÕÑù*^î;R[ZE[[bG j˪dÊ’,`GŒ#„±ÜÁH ìˆ1¢6ŽÄŽX*ÓDƧ›5ìˆL ÁØ'Éo‡‘?e;²¹¶©µ·­/ÆŽÈ 5^ìe±±Ü؈;™ÐaÁbGV:wp;¢pTUõ2LˢÎ|xå(¾lìˆåø´ˆæŽüä¤xYÀŽ üÕ®VNÆ0Œä÷ ;Òä„9ì”H€H„ ÇŽX ’ñdÌ;òíÍáj`G î°¢ØöÁŽ˜H;òúùƒ|ß2K숙%vdßšm˵“Ôä%rNŠüG ;‚5O²TbG(CŒ|„í'ÃævÃÇWGØk&ìÈó;ŸÊK䨑'š÷‘`Ÿ;"]¡ŒÁ¬AÀþ±#Ézömú²±#Ûõê¥#€ÄŽh€H†ãÂÄŽ <U»{%v_þñà/¸;BYl,7vô7þpQ`Gþ·û¿ã‰yvË£¨áKÂŽü­1b`G4@$Ó‘ì`G|a"2É—Ša˜ˆÄŽ0 „(;Ø#ÄaGðáÿ~÷'ò¡ÄŽà¼öWûÕV•ØÔý_ûóÙ`G–,“1Ÿ;‚N0ìÈ bÄrcG,ŒäïÞù1eìÈϾ®›1ÏØŽOC4{ìÈôpØÈj¨’öÁn;ÂÐ;#®þ$vdÓ²µU%KgÄŽà¼#/úf‰,¢X¤;²ºb܈f‰©(.£x«;B·3bG°H¦S)%±ÝØ‘¡ñç¼óåbGâñÄZÝe‰±ô^ž;Rœ,,Ê+T™sÝØKiÌÎÀŽäåä‘IbGôR©„à `ì­“ÓSóމÇ☎Œ“K`G†'Æt´j­‰¡VØ#¥Cv°#S±1vD%ÿÂŽ$œ";¢ýûväwCvÄç§ùÅŽÈc‘bG’9¹4Jv$ËØJOc-ZìÈ’‚RŠaGøsv°#XH´ö"ìH„±9~°#XtIaG"ì}%vKR›EØ‘;bEØ‘;’ù)ÂŽDØ‘;aG~7Ø‘çôO‹;ò°úi©µ8±#›Ÿ"ìHö±#ôÓübGt"›î;ò{Œ©Õéi¬E‹ù:+G„É>v„ÓÓ,F쥧±"ìÈï;ÂÀbÄŽ,/¯ÂZ‹;’ÌM6è…aG"ìÑ,±#1gŸFØ‘¹P”³Æç'_ìH”³Fv6ÊYãË1ÊYÃ_£œ5D_…œ5è{™ž—(gÍÏYóåaGfάLt$ÊYc-lìȥΛlÛÌ2gͺšUt 6g÷¡ÄŽpzš…™³¢Ãx(±#*=ö¯/Ìœ5ÆC;¢ÓӨ댛³Æyø{˜³F§§Q[{1次ô4V”³&ÊYóUÊYS㤧‘ØòÈEØ‘/)gÍcëî‡àZ¤9k¶-_ߤÕbÌY…NS嬉rÖ-Øœ5¯ß³R-‹1g ìÆ}Z_D9k¢œ5v›£œ5E9kB°#󛳿»¾ ѽðsÖl_±LŽyÎY3>D­šcΚΡž»öžý}ËY“›È¥AžeΚ/ ;ò…sÖ% Pm”³ÆŠâŽÌ-rìH:-àKv Óîg¬­`ìHZ¬¼tN<ÇrVsÚ)Ÿ˜vÄÒÛ† úbGŒý–ì<å`G0,$nÀš;žÐH~„I*r̹õ¶Lt0Óñ´U0kì*×ìª;t «K–/ÈMÊÉZtØKëÞ2èúh#A 1q2È„;BÁHF'ƸÍ.òö ñ^@ý˜Wˆ?ìHY~1ž ð^%-‹‘gލ_]vÄÒ7­üÙ;"}cÖœ±#èï=Áݡի_Ûµ‹T»0 ‹;‚=¥¬%g˜Ð¬R”RŽLõ”lýd„kðbG0‰ø§k¨gÊqÇbÀÑl o·òmÛ *‹–È1 ÁŽ`½±3U‡Qײ0û&§9IQ‰ØsÇŽÀ@(ºz¾ÛßÉâ3…>Jà0Ê ä¸ ù¡ÎR˜d;‚ùb ¤7)1¼Ò U0"ÄFæ7…·ºx©ž!Øì¾ëÇÞ'Ž2 ÆJž7B°#Øõ-b”prÆŒC 1®ã‰ó j OZ/‰z}Ë€ b9ŒÁ:iíkçE…¥Ž>BÝÜè¶`i=AŒ„(;¢ v}±#(_QTv£ç˜ªŠËË J±ìo:.7PÃÒÚT*Õ*VNcU=:ÅgKë8éÈ\PØKû*ôÕôa‚°xFò#S-”ó…¹q/b{– MòÅÍÝ í×øÉꊹXä²÷Õ5Ašñ$DÒõîÛ\?–ÆGaAœ'¾Ø‘5•+¤â ÁŽÈ#X„´d0íåeÕ—;oŽNØ0M 12J±'ÀÁHˆæŽÁ€óFß×ê»W h^¶ê@‚¨¶._ÛÈÁH`¡–:ªK’…ÔÇóí×ÕÆÔ]BåueU'o_d¸¦Rârç-Öò˜ ‰© vûY~Ø(Žõ5«¸@vÄr‡i¬jÀäÁHvÔ7CõÈQº_;Œ[zÚÚíYKë`$k¸@Ö°#NˆE˜ ºâq.(•VÃ8 ÁŽ´ taÒgH*ºÇ9«Êk#0­TƇ^0¢b¾Ø‘Mµù¹y2ÆæÚFè2¨¿+]ö:Á Ù»j d«NìMò¸`=3òë›èDëEÞh K–a#ÃæüTÜ{ê`$E¹ °#W»[ï@)hFP¯[µêXËyÞ˜Œäàµ|ÜP³ S MÊ>$K_[ç ¶ °#z¬ÇkË*IÈKG&-v·|â‹y|ý^láóBD“k‹–2´ÃV9˜;vóˤ 'Vd—¯+«–w”!ØØ ]=æ|Kã'l½;ýg #ê±õ{eˆÈ B-|vó,Û!X˜\íbÄŽ@.ñ¢‚ù´Wûö08,¬ÖU»Êű#„Ç[2@gµïXë…Gø`[ÉYÁŽÀ.ý÷³²º|`íll«ŒI§ŸÛö8VÛ*°ŸÒ.êÃ7NÑF#‹ŠSÆ[Û;ò`㮢¼ü×Ïg\ÚxŽ8qu¶ Œ(cLB°#o_<Ì’ ’dSíZôHºBnÚ•›ÈE1~‚]Á…E{ÂÆÑ¦ ó ¾µùAÉ1;Ø‘ã­xC]>ªEîçñ±H#iúåÉ·ùškϪ-«+–CÚ¼qá×óÌ}ÃV”Ó‹Aý äÇW;21=)ß}'쬋÷•Ú²éÏö<ƒ3 d» HäÒ¨bBÙj8°v»1b侨‘§š÷Ks:;ØœU_âèÙ-@8ÃDçÈ 0þµ‚yáø›l„Àì‡FÆ×Ž¿Á7EÏn} –6é z†Ç©‹œQMhÀsBø„cG~rä¾M‚„Ç^€¬þÕÉ á¹mI‘‚ùàÊç¼Ñ`Z|{óC–ö"sP?ÌÂúkÍQ™fO6ï[¥‚2ê¶Éàøˆ|âÅŽÔé`$XÚ ŒQ,ÃY€DQvÛü_´ü'ï!¡Üp<|çÒÆŽüÅÞga÷~Ör–Ê' Gûö…ÃC÷èoÁKâKŸv ö†`GnÚ «ìóÙÙüØú=8^ëj=£_ÀÀŸÂ¬2 øìÈ¡ë'‡Ôå¹ú½±²~mUýÔôÔûW>©s6Ê3]vä–Š Ú‚¡‹(2,BzcºldbLßàÙaÝM§¦•wcGÚº;le+ÌKÊ{ѹcG8tv„ÞN„½À  ²ZzÚSVŠþvIaYi~‘²ÏìHUqyAn>º,ßDUС8%9þØi±±!}§¡“·¥wdP½4«‹¡ tÉC.jFI²(?7ãYÁŽ  ¨ðW9ñëX€t„`GpBР–´®?–ÌU¡xx1…nHÇbÄŽŒNŽñPC’äåNŒq/0¡ÅÉ"‰d„×I^]˃Úà'ù ’‹fD| mVXB‘׬±Æ¤¾A×”¾™eסQ3!ÏF2?'O¶%‡7;ÕÅ) QI²…í•“VZ¶8ß5 sÄŽXÁÀ}$æàè°Ê’[âž…E‡QmîÅö£ÏPÿX90•xëá ¬RÅFÀh4êHÄ_Q¬èKÿèàˆ³)Ô`&‹F4ÊÕÙʼnêbW C°#$ì·ô`ZvF${Ja±Ém2w솈]Ø/°ÿ°´$@ .ÖZ5*úˆfwõMŠø+Æ,d;‚5)»†_ós’]C=¬ÝÐNB÷:ó´¬´OøJ›z…ø‚GÙ5ºá…ÌñDJÅ숥]­¼­°Ú±D;‡zdÒ¢ª’¥øJ–=­€jÍ‘CÊ[N†™Å}ÁC,ËAÇ-‘Hä¬rû C°#x.GµZdà™†%Ë0¡xÂn¬½ª¢%øÊR wuÅrK¹yZyp g––´övˆ *“Wc ;r»·CKf5öá+–,»ÝÛ>&‚­>QkaG0D VHèWº‡ûth%ý$'àË ÁE³qf,4úåx©ã&×Lý¶.V|x‚Õ‹%Áë×TÖC5𲯠5k$Ô&;isY€!hŠåÖ[[©@! b2pÉÆª†®Á^Úx"¯T¬ùÀŽ`î8½DwÃÒº…“͵êô~êÎ%,rLßåÎ[ü¤VƒN ºe>ò¯Û˜6Ý¥æek°Æ°xµCO5VÖß¼wgЧ‚ã–º&íÓw¯°=‰=Mq©ó&?©S0”Ì%l8vÝïsf À¨bÜX}Cûc› æ“w.sýP+ËJ*/tÜpž(y.‡7kجù[àºrcíšöþnçò"'vÔ7K>;½#_t^UQ‡ oÜ»;MöXZ]bfU$ge¢ÀæºÆ¶þ.Vmx²³a#8m9ŸQdùÅ«+—_élž°W#êiªZ‰Òñ'–Ž;ÂO(CÌbƒšñðNg§³õðd¯ÛÓ¼ °#Pˆ.ˆˆ MR¼`¸°µ!½Ûg¾n¨Y…EØ'"Š}\PØ‘6ø°u¦cËòuXR|í_³ ç 1)Nl]¾#ÃgŠ2I(ÝðP¾UÅKOÝ¾Ä–ÃÆÚµÒ‡4wì8Ê ëkVç&Ûo0G¬p)LB°#–†G8¦c–Ææº¦·/°e‚z°zQ@†d ¡-!€÷¯Ül„ZtØÈp™Nk‹~wð”È3ò`ã)ǾâØ¨ ë³ai-–%ŸLwÖ7Ë´\!ØKK6ÞhŸ_[µõðÍS,¡Ž1¼#£oœÏ€°g ó Žµœ#ŽiåïÜQ†…wʘà(ô NvÃ";åéàùëç?fYY¼dWÃ&ÌT¿c}¡Cç†`G ¡=†šnÚÕÈØwæ×Vi‘{òö¥^[$¦¡¼d 9+[ØèÁ÷Xô¾ãÑT«öÉæýtGnž–"wϪ-`ÍþB˜µô¶:F‰ ZèŽw/ÑO4 ¥®IÚ{_qìèÍ Ÿ°A¾¤ ô‘u»ß¿ü‹}˜:Ѐ0wuò¾2‚ô†¶=tíßàa7VÕŸ×z’—È}rã¾óm×(UZ?ùÞö¯K‡Gv°#–ZÆo±IßTUßX½k©'#„ K&;«’W{žrC>ˆã•B÷ê&bXþh§Jcñ±7†ó»©z% þ×Î~ÄÃkA áØ‘¯B¾ì¡Æ]ÇZ.ðñ ÊÂÁ1A†™y¸i—¥%­ŠªJ’EïÛešAÈ?Ù¼‹„Ïx‚yœ˜šü×£¯ñEΉ[–7½ræ¢'æšÕ2« •-ìTÞÏŽþ†¿’)(!†¨Sž°æŽÁóO¼ÅÂ䉿}ø·Ôã‰Uâ:4kØ‘7ΔŠìÙ­¼|êý.ç v×ö‡¯:ôK>£mª] óû…ãoòÈOºC?‰é&Źù8ÀDw†=XÔt3IÍÀy‚AïúFÙÍ£7f|xrŒ]r(ŒU7>5iß|Ƭ¸jXÔ:œ1=¼*ÊH,629æL‡ºlGmcö‹úªÁðwd;bxÏid¦S)É£ 5Ò_OÅÒiéßÉ!µÂ±#nL‚;˜ÅFâ"술/ˆ±,÷[æf;bég6Mð5ê Áޏ•í²!9n7s8vDüê3¾FÂ+[ØËÎP“òŽ•å$¬±ôoãZ*ù® ŽD2šžpNÂ^ÊÏI} ÁŽ`Ž©WrË`wUaF/#vÓ'c~DYl,í¥¶QRþ’…4ªÐŽRPʃ(§áÅDË$2Q$K¦(IXÒγfÂŽik\”VŽc›Ì;b¤­!F²y†vYŒØÛ.qHBö°pº q!£ŒÄ‘H°D»`÷øÈ$õ=5ÖvÄr§­1ª2ÖXó±ô…—ĺIÂZªÇ ‚Wf¨q@Žv—½èì`G,7epÌØv«°ùL~§¯cJ`% k¬P숥­ð ™c$¬±fÂŽ`}ò»\^jX²Œô#!¾}‚„[ZÞêi“âK–­r'¬±B±#–;m1bàH× “:nŠÃ1m”«)­ ©9ÓÐǸ‚,—ÃBÃŽ8iküÕ±‘°ÆZ`Ø˶Æn–C¨ê‡Oo?×ë,6–¾âKgƒ°ìÉ-åx±Óɉã©ËHXc…bG,w†ƒ8‹ x]h¿6•Jù3ÖXóp¾Ø‘ÉûcôråÒº ÍÑÈP# Ússm#Y;2m‹ÒvÂâ(ݨ¢ˆ¢Æªz_F†7ÇÄ–º&i_…cGŒ 5QË•¡Æ¤dNŽLXce;b¹ÓÖ¸)½Ü±B±#–†¾ñ £4ðÿ¢ÜŠ÷Ír¬å¼ Í(‰#‘è 5W=¿ÛµîjØDZR¦­±K8Œ)a qjôÁÆ]Mf¨1ÈHXc-NìˆåN[cŒ…‘°ÆúÊcGÔ¯"C l¹'µ_Jp ÃŽà×įQKE?:'#®I*ÈË'§5 ª×Ï :15/[MŽ œ¶&3×Χ§70Lµìx½vî£ ŽœÅæfÏÝLÀ0ó´þææ ŽÙÁŽXî´5nJSÂK[Å2ÔåÞ {VmY£‘èN”Ÿªr9ÏlyDÞ¹GØWÚÏEà·î{ˆ°ºvâªÈy*‰ßŸ˜žÄ 9æºQ£‘°ÆÊ"vbù㫼µMƒ…mÜR†`G`i¿püMçÂÇ0÷ ªvÒFƒ.øèê1ß3!–ßó;Ÿ’W:áØÿ2[“Ñ|ÈCƒ„`G,w†ƒPÏÃM»5ÇáŸ}Ý{`'¢,6–eÄ[ ­ßiùÞö'tœlµ)‚.'×W¯2쫬aGtÚš÷äÙ×gu$KÇ3ô Œc+…cGŒ´5ëîyƸ~ÉvÄr§­1ÈÈNbÍvDÿú–Œ5+‰#‘0e ;‚#žLee±±ÜQF ÂéŒýÓ¡ä ¹¸ ÅÁÊÝÒwÔ2m›ÒÏï|š8ÂL"ÛÌ»qªýòôßþÂæh–KÃÛï>„`G,¿P0;ƒò‚<€¥Å¹÷YY8;Bik8œƒe‰OVìû;ž Ù{ðÚqJ‚i0µÔ¥På×5¬ R÷•Óï?ÆxËþ/…[Ó;ß8ÍÏ-QþƒÃŽqË‚A îŽD³í 7-[[ë–®!ØK±µCt™Æqº[u¯r÷JJp´?èr«+–S q¬œÖ¾vöÉf–^†Y¶Vú_掱œ´5î&Ù_âñøÊ¥µtI‹=¨ßuæ´ÜÒJŽS©iÛ“õd…òÝ[ú:hÈV¢¤þ˜£ƒ¾Ó´™’ÒIú ó ƒ6;b¹ÿ­BïX>k'`Z0Ë4 jo¸A]Í‹™ k¬laG,wÚÑ0»V^6òâÈpŠIE¬PìˆåN[ãõ¯g¢ŒÈV¹Ëyq_eZôØzÄìˆ×Áޱ2+ÕÄŽ *ÏŽ±2{Ã_ï.²²ˆqBøL:Ä ˆÎn3å-w2Ý«ì6>×Ð_b6/;¢›=ű$_4Iæ/ ZŒØj¶¯wµ±jÁ x¥*ñåeF¹fø'.MøžGŒ€¯g‚‚Ž0G™ïFʘuB±#–öfùö1?'éô¹cG,wèÝû¿X6^<ÇbÄŽXÚ½ÇI7ä=e¢¡/XÉh’w±$`çñŠÙm©û,/ž#;b„áªâÑbì‘yÁŽ1å˜À±º¤‚e]ßè`¦;â :be;NiñÌþ\%2Ñ`í‘ Ð˜HoÐk&ì;1QšjK+óÝr5;béÓ—¯‡ =e7Véí¾ÎiFi¢ #ôY†±I—U™n<‡ípìœûh( Ïæ½Lv×U ÈWBoõ´ù L#舵ð°#–^~¾oÐkáaG dïxŽ8è}åÐ#Æî€ˆãó3ÐÕ®–i?”Æé†>c¶Ò ºë¾X[Yo€ñ#àxYEÎðáHAGè3v«/8 ûBfi!š;vÄÒ×Á|-.{I™høë…ö¼Å$QÐúl„a‚A‹…ÁªâÔë}¡k\î#,¥K7¥Aȴʹ•` ÇŽX:$’ 5ÄDAG˜£ ="©Igº‘O²‰é¸,âX0aùmw±fÂŽ@prúh86-kd0Œ.ßkhìÇMuÌñìÝ«&*WWUWVµºbs<¡²eF••¡Ï2ôˆ¬ ·{° ;¢Bܾäý«£…uèÕ®V‘,/3üPÊ^_ÔBÃŽÀ¦ò`¡û×nç%íïK.ìˆÊD㤵žJMÉ >–(‡ñ¯r«†yÁŽàŒsøÆ);à­›v­Ü$S>Y3aG,ï¦Gñ2«ÂÂ`a¢Â«}tÈ:b-Zìˆ ="Ç"'‘óàÚ†}aGp}ëÂ'òʃ¶wÕ}ÆÍ~8vôѵãÝ~ÇœÆÊzvÞLŒ:q,L‚ƒbü`d·q7ÈÅÔŠÈ¡¹bG‚F3kØ+‘¨"Ÿ…eÍ;bé×CÓ–ëmT,zofÄŽXvV§i9¾¾À+‹Øj9T£1A¨Í`:šžtÃGñ8ŠÉBiÍθ‘ÇP@ yޱ´§sREÌ´ ‡eïñEŠ!vcS.ÿkž“«Œ Sƒ–Ë[!˜&éÍ‹4⤳I;í‡j1V5ÆjÌí …J(ðp„Í䂸ÅbÅy9žU=#vÄҺʀ:ªL+~;/ØKû83u˜#ß5¶H±#*™ÑØð¨ˆSÛ Q¥(,Sbå`Ëò‹n‚×€;¥èóŠpìqì˜vIÂDyA©w`ç;bi ­’ JL“cBU†ì>:Ø‘’da¹ßrÍvÄÒ{¶k°WÜ|¥)¤ž!°üÐÇia åkÔ‹Wa…cGˆcÇà=—~‰'pòNåŒØ( {C}ÆM… èÚ’àÕa§³I;spŠ0ng°ž»Õ<:}L[ØA¾} ÇŽXzI`v䙓Xã™J¬}5™ÁŽ`ÍW•,‘Ñžö{\…_«K–xÅÎÄŽXιK>ÁˆùÞä.4숥'èN_‡½ìõ¡LÃÒZÆÑÖߥƒFfûql1™ÎÆÒR§hc£AJ´öµsF0K/ ÌQÂc=†cG,}Xmím“Š’Ý4T-TÞþNy–ÃöÁŒ{9Î v„8b¡j³Ö¦Š¢²å5îü£Ó7{ÚúEþ/´gEù² ÷^ƒ„q £j,Wõ2Š+€ ‰ÝàxãÞ>ÇÄêŠå^m;#vÄÒ"â®;¬ÖCƒv ²óvµÈÈOฦb¹WÛf;biøÈµ®V©Ca ­«Yå5Ýñ#––„—:nª,‡™>Æ!(Ê ÀÊpÿ®Êp„Pm¬j08b‚ÜáaÒ˜ ã~¼®tÞâíµ ©‹næPÇ`ÏîÛÂÂLci5Uûôq¡aG,½ËÎݽ*­èb „2ÎX:ò“ÅŠ{Ö;ªÖÂÃŽXZûŸ¾sYÐ;Œ˜!0¯wßÖì2‡Ž5+ÖTº\S©) išV&ÇÖë}™Î;biÙ{òö¥AqŽÛê7ÀkØKëb#v¾„ˆ8s÷Š&óÛ뛽‡¾Eб´r#æ5 숥}öF|…æšÕÍ"B»¥á#‡oœ–Z[q\½Õs@†uÒÙAïjØdœÑNݹ„…*±#[U˜ŸuޱtXˆ87ÇêûWn–ñ+ʨt6âJ«Ë»­,bG,-”^;ÁͲÓÜgˆ/,¿Ž{zåñ+oÒa…¹qF` i‚¶xM…;BôyË9u0Ø,B½uüþåÏzÄ»óGÖí6,ä–Þv‘ÎFU{éÀÚ^WG6±#0ž!êµ|Îl5¬./^Êš ;bi7í§7NOLg,Hr|yºÇÃ7O_°oŒ¡w£Íˆ±ô.³±hNóQ¾÷>!;biQÿæ…OäY6áÍû8B„/5‚¥qÉûÜ}|ãÂ!Èíy¸i7GˆpF@1y~îxªy‰Gkg;béh Þ¥ƒer¿Û8±!ÓÙP¿±ñ Lââ8vôñÕã2 èµ;¼0A+‹ØK__¼uñ°¼ÁÀÔ|{óC^3/Øͱç•3ÈëPðz²y_U±y‰‘M숥qZ\þ\>r1N8î½~þ sèP¤Óìot[`÷òé÷ì›IͲJ'¦1.î]?il´ õp|éÔ»òMpÄkpwPLPÇ8<·í1ïåj8vÄÒ¯†þúÔû]ý ãÈÏɃYèÕ¡3bG,=‰gï^•Ø‘Ðéuâp°#8ÌB˜f+Ðöë’Øk0ï #çôK8„JìÄ—÷cÍ„±´$¹Ø®3í:þÈê⥛êÖzÝmáØKÃG`±L’‘£jC±lŒK9¨EÕx+ƒ5Û îÇü]9ñøò²ï=í¼`G,ç’–,4‡x,QS²Ô¸s›ï´“ÂvV“qï“؜|ËÍ×>Ó=#}v²$*•d€#D06p®O«:v}ä?òºÃ±#–¦`”¯hbšŠœìLX`úÊÑv YúR«0×Ìù€mëò'Z*³’¯Û4kØK{µ¦•ë^:î­D"a8|Sʿϓh†oÃfÄŽX|ÄCñ+Æ-—z‹}•é·ÆŽ¥­ô¼ %Ûâ!µÉׄÊ©ž¤%2ÑŸ÷7Ò¢9êÊìÂ1Ó° |ŒEšÒ1».ÿbÒê qŠeb"…"rÒ3cM†F7µ¥¦S)ىѦ±;ª¶D<ÒGé/ñzJŽi ·™Žkv!p"°xÀéª$G´‡®J5Ÿ>‰$‡cä$n¤»×{eÌUP2¡Nñ ŽÓªŒòøä(iêÏÑÒ¾a(üšˆ%‚F5¥'Å0‰0ŽÓši*WóÁKÙ}÷Ë^p s¤†z)ˆ£Ôg9Á§„ ÕiÕÇiXr9ºñAC1Žò•YA§T`!»XÈàËWd‚´,Í5}Ž+Žþ£ =©Gõ!Ì,}†]bê,½ìQÛøô$ì<Ô´;2ê?Ófé$XA™dG5;)îcܵ£«Êœ7¼€6YŒ¦öMPUSý695™›“«mþ}tsÌ 2J&ÄÊÉ÷×Xz®ÙE‹mÄÅ`†N¥¦PO¾'¨R†£Â™M~.håL¨ÈO)‡c`9â‘©ÆD±¦è3ç/ó)¦— ø¢@An2hkâЛçAªÉ>båŒNŽé…š´rdt+l éF=ôIR5̨9NÀ>F%(²i¡L~®¿ªÆÄÙØíaÙñ´ìQ…ˆðE&Yn`e³í‹jEãgÇ‘ð‚´º‚úÈùæÓ:(”¯ø‚\’HG_|‰å†rbq”×ñáq²Õ” Z«XÌ”jÊí”ÒL r|bP1G¬pÄzÎWGŽàÅŠ/d?|õÁU‰#J¢’‚¼ü`Ž™×Pr.Y*686Œ]V’, ÚÚà82¡¶mq~ΟAJap|xtB÷1/iÜóJŽƒã#XÕ Ä™›ÄF&ÇÀõ„@råîðÞóѾ¶9æå‡l4¬| ÔS4°eK [¹'¡^’o†zÿD„ÆÞ§”º¾Uañ"L*éÏQcC‡ˆ]™ÖÖ²שb¨[#ˆ#ú84>Š Q ¬ 8H¿ô O(@Q^¡q#ipìLbkcmQf*e L” RµÒcêÅhA>³ø’‘ö ’°éÌÁ̼WKL¨§oņ) \PU’#çŽôV546Â._Ø«åÎ8 ™ÔGå +?hQ ÿ(Ù•_TP8B Ž”ä£EAâ‹Ê ð’ÂR_ˆ¹5;$º¥½&™ Ñ(FE4Ì‹aŽ‚VG0ÑÒR±÷QUÐ1§g¸Ÿj+My¯JªÆHZZÚB &àÅÖäj#ß ¯æ82‘YÁ3ñ • âØGžÔã‹ö°´Peto¾ßàXêA´ÉW,íÛ â8"8I9FrX£ı_¤õÅ—XŽâ Ï«AÖ—º‰DaÔSðr‚æ˜_^p s„ÌAÉ2ª2˜ã … A1¯9öébPyežÄ—‚ã(Šá@± ¥ C?½€¡9töBÎ{Sm2A³t öâßÕÅK â‚LÇÙ¼€JÝ {#ˆcßÈåB8öŽ*a²¤ 4ˆ#¬PC…åZÄU¥…ê ôcMIEya‰¯éˆª¤ˆöE{XZ9MØÓ÷%"† eæÂ1óZ‹÷é™ÏtIQ0Ça›cZA+9¢a­¨h|Çž‘~Šá·´°ÔÆAQŠ' P[RÙ~e$Wƒd&\TåkÓ‰¨®œ)Ø·XÛ@÷ÐØð²²ªŠ€ª@m‚cmP§&ïôµõwk­W¤ 8 ÉÁõø¾dW%  µ´»;Ðuo¨õT—Ù ôÞ™/•-l#¦¨Í‹/!‚fG™îá>ÔƒbAZ[•ùÿÙ{î:’#]°.pá½!CA$è½mïÕRKÓ’FšÑÍ›™÷Î[wöÌyÿbÏžÝÝ·o¼éiÔ’º¥i£6lv³é= CH@ ¼j¿Ì¨Š•U( —·Áé£aãÖÍ›‘&2"2ã«HõrËheAY(Guc&vh|é<öeX¼é„’óq”€õ’œ¢À ìzGc ³*_b9ïÒŽwzÈÄ žùù±wÃ>Çœù<p$UÆqÜ嘖æ—¸ûù\h¾WÑ&=¯¢Yó½PŽ(†ÿÑ¥½ó5^•éA=óq´(!èHFj:_ì'x/(ãpÌ-žo+§[Õ78Žþw´¸=Ãýý]¨¤,¯d>ލŠ÷h™yór釟€:C&È#öiéó.íɱ~}ï åÑödç{ùÊ"¬ÀØ0ºËSâVa`áVAJçó -­¾Ü?#ó©qÚ¿è=Z&ï|Zb‘[ZwÛ¡Ý}`: v‚&»ù¤Ë9;šF«²æ9;R‡{â´j¾÷ uòŸ’’2ß ¿`@°]šå`‰£ïÌhƼgÚ*R ÎäӣѴԴùvÇt–‹»ù¢!¶mOÏ¡Y3©))!òàhÇÞð_DHnþª(숒:fš2ЦÈ#¸…ÄùÈ1âƒû(‚ò‘¸p¬PHPÞ­-$Zm-.¾o ´@h™Åbâ…søwI_;’¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤”ÄŽ$)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$}u)‰IR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIúêR;’¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’ôÕ¥$v$IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%é«K_>vĶìˆI(GÛŽDÊ1Ž4gÏa¸l?Š¥DR*£¦>eU-ÈÑVbdëBßÀ¢åsss‘HJøPÌ©NÎ¥¦¤†×6;7‡SSÂÍ¢ªHJø¨bäÁ4ºÇÅÐçà87M.câ }œ™›Åp…÷eðï‚£:=;ƒ>˜ëY{6-%ºÜô Óâ1³s³èfz4méU-ž#æ(#šž0Ž3ªñáˆ453“†«ß©Ùi¬íÌ´xqœÆ-Àqfÿ&r'5ÇŒxp„<ÏÌÍd¥e.½* ×äôT\øêGü/;=>'¦§0×á´HŽcS)))™ñUÍq:;=+¼ØèÔxzjZ\”É" ÁLÆqdr K#œ#Ö,„0Ü(ŒOOâ߬´Œ87q9ÑØôþÍ]ШU(Õp-153•—™Îqxb®W\Öãä̘æ/Ä1ñ441‚ኋ ‚Q+ÈÌ /68>½/Žø7g!e²šÀMOæddÇÅõM0aØ¡L Ÿ3C5ÀÄô$ºY˜•^ÛÀØLUnFv8G¬¬ ðáG¨¦¢ìüpŽ5ǼPŽ‹¤áÉÑ™ÙÙÅpÄXÅEab¦çfг ‹õ B‡sœ™šÍÏȉËn¨t0+=#.ÌÐÄ(þ]P}õf/Äq|z*º$§pé­‚/õvqQÑ‹ä881—HÏd1„!›/Í-ZzUèãÀø0´DxLJ§fgV,ÄñÁÈÜôÌpo‘IFúÁ.Ü(ÀpŒMŽfçÇ…ãýáþœŒ8.’ —ðï‚ê+Ž”xŽ‹!ø½hZ‡¼g¨nÑÀ±t¨8gŽPãpÈËóK—Þ*ÔƒÚ`8ÂU¨qü[œ³€}éêEÃû¸HZ$Ç®¡y9qáØ7:€Ã† År3sââ'Ä‘à OŽU¬/voð~z4½4†Os­,( /Ö9x¾Ä‚Ûœ8RçÀ}° ÷°ê(Í-ŒËàî@O~fn8Gx/ð`ªv¾v`ºªpex1˜*ü»"·8¤ †ëÁðÃü,ŒjØÆ ±±ª.*_£mYe¡Ip„†Á1Ž„‚éêr\$Aì!‰\hqt9 9–òíض/†¹Á\̶}vnvT䤅¯YîmЄ> ß/’y, Ž)‘”D}/†®Âà£d\6¡èLII‰K”vÑqá…CÌBˆW-ñˆ‚¯&}nìˆ-þ;ß ùë ‹9§˜Íe+„Œ2Ë”yʨ¨¾[ÌR‘û€C4 ŸË'ó…Ò¡¸]©ó¬mZùüq¾}/ªr»©ØÍ‡< ÀÔ„±iv±ª¨aþ³B ÂÌì¬Í³dEÒ‚jƒÎWU¥FBà…b<ªÝ0?GÔ3=;ã‰`¿$›šà¿ç;`BU`Jµa¸æ300<•i)Ñ@«€†Q‡(ФQTOô1‚ªüSIA#–j Wf4=Å@·ð,§tÌžãà ÏÎÍOó;]ókLâˆ;àXt61:9Ž]1‹–F~ÐAí¤>GàóíÛ‡ô›þ†ZšpЉ2˜#^(†¡ðëLµ…yÈçÛÒ¦ÑÒÚÒU 9ØLŽ ŽéÅ9þy„.æÑ^]Tá¯j|jâáØTRœSè×ýcC¢6„pE^±iCÀº‡ûèo” < ÃºÆ r9*Yin‘_göò ²´&Ätû9¢ñãäK2Ò2*óƒçñÞàƒ WÀ0;~YÅ2D1°lÙó2rJs ýûÇé´”ͨ, 8Á öŽ ÌÙΨb%–;ŒOO`ÓÈÊdýŠÕþª 6=Ãý“3“Ô.´gE^‘_Ÿ I1V˜Ð]ey1øwºùㆲš@Žh+¬’œB¿‚#ä™9Â8Vä¯0ì]×àƒ¯î]™WâgŠªzÝÕªÖW–éwûhëbUe&ǹ¹Žî1W/a¸`_尽﫯¹Eói¹k]7ùïš’*ÿ~Ê ÃåTe+¥Šá ¬­­÷îˆËÇtåÞ þ{mÉ*ìðý;vCÑÑGpDUþ¨&¨g¨…écZjZMI¥a0\Ýý½B/gT”ù&ÝC½ÝCÎÒÆb\·¢:°ñ7Üá鯰Ž< Üxp‡?î\µ1°*H˜º†#{CÙšÀb×ïßfŽù¥>MŸªc Gj{ >…¡¢±4Z{;ا…á@UþƒÚžá>(vD¡% Ô ßÞêëÔzÉQ'˜ ÕÅ'Vœ{ƒ÷ª2s6®¬ ,¥㘙³Vq4—6tNs÷-—¡µ¿f«¿*K•¢Bú»ª°l>3t²ý2ÿÝP¾Ö¯p %ZtPHØÒî%UQ@m׺ZY“ƒ]àYa{_g—;×–6| âãûw¸*p\]TîŸnÐÕ{7ÝbÕE+ý†Ö§ãaæ‘>¬A$Ö–®òÛÐ;ý]w: ³ +gkå?;ˆÄ­Þ»lC15›ËëüËôIëy×¼ØO¬Ûí/ºÝïv—Ë1o{UGÐ¥Îëƒãôi‚¶¬ R˜ÀKw[øãSë÷øË`í`¸à*à`Ö­Xí_¶Ì÷JdXm|ÛÔ} †m誢r¿QjìicsŒJPÆBnëë„–c‡¼0+rèçx¹ó:›cKMwy ¢ÀµõݵtË T1×þ2×ï·C$œ>ÚÊTaðmÜTÈóñAúˆáZ]\QW  ÏÞ¹Æ »À2Í=íwúïñGp„2ôs¼zïF¿[MКbS¤;ï·>¸Ã^4ôüÎU›£ßi<Îï[³Åá#MÒëct]Ùê@;Õ~…‹¡Uþ¹†UÉá'Ж(fXmp¼ÜÙÂÊ#€¹ö«&ˆÄõ·g\ÏaCy_5AÕŸl»ÌÊäë[žô·jäÌíkãÓÌk6P5}ÖvIÙ]Ý¡µÛÓ(ðÙ­‹üñ[Ÿö—é¸ÐÑÌá¡m­\hqù#þûðÚðBj8~ëüæ¶güe,%`møýh_š»Û`øÈßC/Áî@Í6ÿŽ N‚R_.ýÆöçüUaù\¾wÏLà¡í®nð/m¬Ù›Â€ër°v»Á.ÜÙ;¼c·0H…ãýK-£Ì1-óÐÚG ÿzá×ü74¡¿UЖï6Kމõ>eÒÞŦg܃‚ô¬#uÁÿûùwùïßÜõ’¿8žïh¦øqÄò¯-©ò—üðúéîVnsź-•ëŒpó ]mb¡A ¢˜ÇerUû´¶v„žÛ°ßÏôAË)Þ<>W¿ßïЂãù;M·´R%ª_YƒéöW‡–}ZÔó|ý@ŽÿtæWü÷óºÇ0µ¿n>Égï«e°Ù!‡!Þ³zsàÒþ‡Ó¿tÿ´_Üxhe¾ÉÆUõ¸[Z¸Ð›Êk·WÕÅ`§Nß¹::A¹ ŽX¶þ¥}úöÕ&í¡ݳöù'Nï»MŸQU+óK_ÞtØßr¸%¨ý^¸Ç¨Ê¯ÉO·_iì¾eÓ@h½ÍVãà[ªS·¯€)}D{v¬Ú¸¹¢ÎÏôß®}Ú=ä¸LÔÕ›Œpž/Üm‚}ä'àebpÄFî%WŽ(ã_h _]=Öå6lWõ¦]AO´_¾q¿Ÿl©X·«ºÁÇqà½æj¸l‡ãÁµÛý„_^ýû²_ßòT๴ŠñÇÿáðwüe,휻ÓHÃM}-È(  –o:Pì™õ{ «=93ýnӧ쬂¶V®‡€ùkƒEC…ô7d~ïšÍAe®BE3Gtðå†'Œý 8¾Ýø sÄ`n¯Ü°wÍm?¿ô!í_0b(°/¨ èÿ9ö#þû[Ûž­ò™ÀôÐr²ÓÝ ãŽÊú}¾- ¼8Ø a×OÀ@½ºù‰@¼ãÿýñ?ó߯o®ÊçKÊnfù©õ{ýKû|GÓ‰¶K“j àp|fÃ^‚o?ºq¦Q/mZXŒUû¡0Q›SUÑÊïíz9°Ì¹Ž&æˆ=ÚË Güï @¯þøü;–ËòOŸÿ¡¿*Ðñ[Ùû‚õ?¼vGP™ p'ÇrH…½ÞξÍÿË ÈñŸÏþ[‡»+ÄJº5bÆ9r™–}d+ÈÊãQ¥WÙü Ã%w¡Ø9;½ávø}è„aG ðÑGŸä@ŸÀa2TʂؑñáqŸä@$ cƪŒv¤otзm4»4·ØŒxaGî+$Á”ñ1MiÞs¨±#èfÇ߆âœÂ\úêìå4U¥9¦¬Ì/1N¾ÄŽ Œ ;!UQ•¥Y0`òº†z¥q!‚‡­‚±Oˆ vQÀݮǖG4%ZŽÞy\;Ò3ÜïžnĪRÕWbÄŽÀYïrŽØl¹l¡OäAg÷PŸÄÙ0Çòüc¹-ˆ&éìµ|„]‡Ü}a§§#—&ÇÕÅœ\z©­¯ÓïÀ@Û Xª×Y;r»ÿž4 ¶Ë±¦¸’æÄôT{Çì´¬š³Â¸`G Tèc Ý뎊Ֆš1€¸`G`‹oõu(üŸwô!Òò|ò,!Ü4”)v…•´öÞñw,jìÛ¥ý˜bG FZ´û• Œ{}Ùö` F[Ûi0×Òj¡’ú²v¡F»[cVÛ&ظ²ÆðLÄŽ4õ´ñQ©ä¸ie­áŽ&;‚…ÓØukÖç}Á`5øŽ&ñ#¨Æ®VZ‰B¢mh‰-ëØ3A«÷nú9b­ó©Ípì8^½wƒ×¾¥±#–ÖK[«Ö¹‘ÄŽ@ü8¶Ä#qõ‡™—v뫹§Ýý~L“Õæž6Ž-1A±rÙ¾@^¸Û lT…;«7±ÕF=MN4ËCµ%U2hz¾£Éõ¤9NÝUÝÀá ž¿Óèß €_øÄŽœëh”b Ž»W7°•xÖáèéAàyh8vï™;Ê·ôúíàxpíFøã™ÛWÁѱʂ²­"~|óAGko‡¯½¥r}•ïÝâpì„ùJç cƒlk]±Í'üáØ8§Ú/ùÔ´Ä~NG³ !Ü&„ÿRg t—QÚöªúroÐwAìHÇÃnÔfù¸¹ÂŒÊÇ;ŽXþÂpÔ¯¬1&;òiëy örÈ9{I>Q·ËØz,ˆÁºnryIÚ]ÝÀP'ˆÄ±›ç=[‡ãsõû9¹Ö>ŠùÏP\h°³MÂäqö¬Ùì×‡áØ‘ÎÁûXh~ލGÆrP¦À^òHQMÓ@4;+|êö•Ž%•ûטê+;[öaËiiш ³rŸ­ßo8rqÁŽŒNŽ¿ßrÒÏšð9ÇDbG 9r©È&ˆÍÆrSøÃ±#ýcCï5}6-v¾TöÒ¦CüšêKðrþƒ•[ç:ÉØ>¿Ûx¼ÌÜkc ¾±õ)c¶ väâÝæ‹wÔבºlµáñ¾£8º rZ^¯4aŽpo°¨½»{E¨ÀxŽÇkü„2Ž0Ùšã«›Ÿ`Žðm°´5GéîYëËÖ<éóˆÂ±#pP@;ÿËöõÍOñù*쯛OÄäÑÁÚíÇDbGÞ¼r´K BˆÒ¢i(ɘu8?¹øžÿ3ôÝ/ÄŽüâò‡÷|1PßÜö,sìøùåý1ßÚö¬ñ0.ØX–7.`r´•Ë!­Ìéö+§o_õW…³É‡) ÇŽÀüuË â(ý/ÔóÂÆ˜v‚ ^ ²Ú¯nyÒŽ v §QÀˈ2¢i/n:ı™úÉ…÷ün,D‚wL­: `þ6ì¬Þø´À|¼Ót¼Q€½\Žé/m:Ì{|p„-cŽ<`+rо·û%ãôxAì¤ þªŸã÷v½dX™xaG~tîmTe8Çàø[»_18&;ò`äáÏ.)±§PKÄ6·÷»sqÁŽÀ k=OÛ Gº1ø½~ÀJ8v~ ãaµËŽ0vÄÒàÝýµ[ÐÉ‚ØxqºwtŠè·¾SÁ”ý퉙©&uP0!Ë€gnzvCEo0adoÜ¿MåQÿÀ‹–L6U<þ©))«‹*Ùï…‘ºõàîÔÜL,f¯ÿ/3-£¶¸Êˆj-ˆâUa¯X“ÔS#)•…e ÝÃÔÀåØkÄå ?{#æ›HìÈøô¤ŽÙ¹Óì¶?7#K.¨yDã l$‚9òñ#”F>!Îiéþ7|±#Ï©XÄÄ•}G“gû:=ëûØÉ gtJoÃÔÿ§¦ø,€™£‹/,“ü )ƒ‰µÊûeA")ÎØ‘ðÚxžæ<ÅÀ Å;â?“…—vDã¼lÿy–¥O|H•h|‰é¤ò ¨Æ™ÙYÿÓ¼”TîÔç2ýA%ÿŸ™¬J?3Œ™ZVØ(š±É Û×xúœ–A3¥ò®3.Á[s”#N{ùe#ƒ8Ó†{3?Gn*&q|*_biÍkD¿Â±#à8$òFãpœ™öŸ\0G¹¿Ü°#ƒ‡Æ9«ýH¤8;Ÿ/Œ«¡a¾‚öÌ!Ì,}xDxˆèÇz½C ^Ø7ê"aØ‘Áñá@d’.l&P ÇŽLyá L¶Ö+ó }°#c:iGC¥»J}ï ,;‚7Ng˜Àј©pì–¡Úö­3£4Ð_ß@WzcÃáØp¼ûÐ8ýaŠ±Ï¤¥íÂAò`œùÆ;‚Jð?ïi°Cy9ƨ†cG Ìš5ª‚‰4N´Ã±#0U·v»1SC~²´=Òp3¦BÍc¼ÅŽÇÖÞ»ssÁÊdmé*ÒuØ´è^€Ž†2G´Jf‘Tª(žy ÇŽ@Kg^Ì…yTÛ¾$È(ئÉ04qÁŽ´õuzÌ‘ªÂ2CÌâ‚iîis\&ßè×”T’¡ÒþY’㟤¤lZ¹–¼/L¢?ìMTœ]`ÄøSìD"Ð(`8*\\ü%Œù¬Oì‰õÖÊõ´·ïUø’N³M†r3°*1M`g›†cG°"nÍÃ1/3ó(Ÿ$;Ò¨à æÙ¥&»nEµñÊZ8v¤ãa7«/O0A'FæXÈ9ñÒ˜A4#þ޹ó°‹þf.c¬JC̱#ÐKœyvéþ“ôe…9>ÙvYì=ýسz3y_«BZ¢4LÇ7.}àýÚùOzjÚë;Ÿ' ¬ðÅ °š¥ÁÜÏnð¨¯pì8JI–^ßÙù+J|‰ÄŽX^\ÈO.¼7ß핆#†÷޹ÐÑä‡ÇWØÆ…üøü».GÃݳ°f ï=;òñÍsî6Ç42h¥À™š™þ—soÇ™½a Ž ÃŽ´ô´½qÆÿ+[o¸ð›WŽòÁ xhF6;ÒÜÓþÑõSUã7]\Èσð%DTÂÄ;ò³Ktúû¨ç€q!Øn¨¸x¥EÓ~¸ÿ5ÁŽùÛS¿`D¾á½¾ã9ÚaWòÆÅ÷9b‰ýÁo—ŽÇù–v~fÎ8øô7ôÒµníAt fÙPì•þê³7&} ¢ïì|±ZgˆÄ>`>ŽtèÛô·/‘ÖìàɆcG`z¤ÿ)©ÚW8.ØØ;òüŽ(tïoí~E>I$väKïßÐq}/vÿÅB3 ÅqÁ޼yùèèôx$?wùE"ìä0…cG ¾®?¸íÔbÅ@ø·ªÈD™‡cGt*”fOƒÜ:³¢œ|èúýÛ÷•96ËP¾Úîak‰ªèÓÀŽàÿ6–ÕPÐk_7ž+Šá9ÒSÓ*œsL±ÚÁ‰ÐC'Êr‹ (;241Ò=Ôçm’ó!=-­ºÐÙ«ê7'ù{n¹¥ÃdÆf°#³ssn¢M;’‰€5ÛOÌLA@9º@~Ž™³m¿7îX$’•>o”6;"“—H숥w TØÍt ê md‰T $RRMÌJvDGÿíùFÄŽx¦IìÈüô±#˜U¤çÉ%à™çW¾Ô#KÇŽäÉúea|4$uYaG°ÆøVKƒEfí\‹®Y±|‰{÷ŠNpÄ ý+uÁ >NŠ·ÙÁ¼Ä$Ñ×Ð8HˆˆN/){Q׬(Wî”æ¨žS®!¹ÕD;}©S—vDbñh U:×ûMMIÉÖp‡Ñ©Ø шJÍ$Ý3õå/(0êném‹]z¢…4ü‹áÂPOLOqÃEc2<9ªR=iJǤ¥¤Êd ÐõéÞL3!ØÊye¹=G Hì ’Ô4â84>ƒ‰q€œÈ™ÊËÈö —váQEËÑ£á‰1îcvzFvz>ö òC´S6!潈ªqžbpƒÎ¹’£ËkZ XŸuŒ±ˆB$ òÈ '=ˈP&;i—p |eÈÿŠÜ"©|±#pÝX€ÑA )`1“ë7.ظƒ¬ˆÀä¥'yKw\°#]œS]ÏZZ4:0;cÅLy“…aGÐ}5}º±+xÕpIoØz¦àhBUvÄpДŒDJ6'RÝ…cGzGbÓMÃŒôŠKO”sœ{ø!þ–« ʤæ\:vÊá®ê££¿Š²óffgyÒAkŠ*¤2 ÇŽ`¸DÞøôœŒl™þ¡4·Hª»pìHßè f {± dž Ú‰nˆ¸ÝßÅÊ+ŠBŠYy~‰T>áØ‘ÞÑ“ÐU5y+ íÐnõÞÕ ÍÖr’ !¿/ÎX+òW@hÁèÎÃ.~X–W28>,LIJÝŠjéÀ„cGn>¸ÃK» +¢Õ-8®)®ÀZ€0똫3œ•eý£ŽÂÔ7‚­Wy&b—ŽÁ:å>¢/å¥}#±,D@cÿ¿tì¯Ã>õÊBAÆ9bÓ»•­½|£ –gqvþ=÷<ÔÒkR|ý~;&ð#Ìòféw°¤Õ~±#ðŽ®tÅ[ô±é GíëÛ…¶V®‡}Áàðûx!ïxØ=ë:4ð%heªg¬b(L A€l”æOŒ¶èÚôÛÕEåPzì™ òíU¤E ÇŽ\êláã¿ÒÜÂì´,±¦ì+×Ê-w°#°P]±ø2FÏí£M7¶B°#°eç;šØ†ÒéÕ}•“Ö‰wl®Xe-Äw`ôjKªÀ‘/LG÷‰B°#àxöÎ5æ»'=C1ogÏšÍ2õH8väÊ½ë°ø4àÐ +óKnõÆ"jàkÜ-²¬°#P€íî…)ú&”j ²¼•† 'Û.±Û ‡¦¹ ~lZY‹5'DÆPV.¯JÊ¥Ûú: }ek½„y¼qÿ6sÄâ¥8Ágàèê´ •:+çÆ g«“S˜ohBö†r¸'.G¯Ãu;åûI!ØøüŸ¶^ˆ5C+®XøÒEϺ¡ TÉ„l°Ÿ€î±öì\Žc­çÝËqìJ ‘!"aqvž@’é ĺ‚Á1z ȹ}Õ}£Ý†ƒÔ,Ò?€¯‘˜';Í ­³gßZµs ŽŽ&ÌÌ9âM•‚osôúYÍà+øEäú̆½ða l 誚Æî[ ì@ÛÔl³´:bwnÿʼRë£kß^U/oË ÇŽÀ^\wï8 «j®u·Š{p —Ñ—Žiéioq9¢ËWÖ\íºÉþ ô¡aƒAtZ§«µ¦bÍz¢n§ø†cGÎu4 ­•»iåZ<áÊוVo«Ú€ï4~Ê×x9Ú¸O œ((À:J‚Ýñ+ OX Vu‘cœùYyP€*—Œ;ë$#VvjðŒûF;8î]³¥±«•ñëЄ/l<ˆ?ŽÞ8îuaf^MIåÅ»-|´¸¹¢ÎHZ‚W ³h»!ПîÈØ°ƒž ;;øÖ•X${gõFhcJb+àNÃéµ.;oÿý–Xæëš ƒ#¤QºŽ ÃŽ|Öv‘í/46¤ýìík,oP‡¼aÅìHÏPß{ÍŸñGü°I]ãåèsøäßÞþ¼¥Ã–:á“æ˜•¿cUýñÖ |~sYÂÇ7.¼?é>$CÀ¿½´éô“ñ#^?u§ßqH`#`j!„Ì €Õ†› i—ÍÀßò–¨ïî|5ï§îŠÆ|Á~AYŸ£rC«„`G`y¥´ã[ròY o×Kà±?Ù~Åå=P» ¢¨^†Ñå0¯zuuvdxrìÇçÞq?Ùj·C 3bõ}÷+pÝ¡…ØOPWÕÔn?që l½a†ùç3¿â3IláäÉ‚ëgÖïŦŒtêg!„0%lÓ£i?ØóuyÝLvûˆŸœ—ÝT^šSdXø!ƒ÷¥õºÜy½×嘗‘ó»û¾.{±tìÌÓû-'¹GB¸¬½®Á…Ëñûû_Ãï7ŸdC†±Ú·f+~å$ÑnŒ±ß ÁŽ`!KŽÏׄÇàø¾‰?~zñ×¼Q‚„AqºŠÀn¿öL˜–ŽÁše %(Šožåo_Üt°¡¼;©¿>ñ3^VO­Û“$qÏxð7°Y;Ñv ¼è ]Uóñ3¼—ëßÜ¥’Öüåg?åwÀ®ˆÄ3½´é0Œ8þågoðç×ïÅ͹—ÊV›¯?>üºFåàcÊßBK¬Ò„aGH9•ÄþòÝ–>7BŸŸ™ýƒ½ž…¶tì,#äœÂŸÐ„à«]­äVáÙéY¯n~BV‚ÁfÿØÍ³Ós³…Çæ‹N2-·³O¯ß#£'áØÊ1IUeça­¡<ãB –PØÂCc| ¬<"Ì€bùàô»?x˜·vÏ©}–z–Ÿ‘C'9êš°Ùi*V Nr²ÑxÆs¬..‡íCæî6—¡RàØ“ªÃv].I5Žñ#ðǦggûç!;-S+HR–[ µƒýLcK°Í š™!Ž©‘Œƒ„$ ;‚  {r‰¦¦bã ŸSG¦Tc1ìè>L ³ûÍá]®Ö_îÇñ#˜nÞ‘¡Ë¨Í «âð0Ìv!ØŽ ©¸°ŽD3¤Ãmê4÷„ 5¸×')JUQÔÛ²gfc5ÛA‡èÿ7:„cGæè€Ñtx`¤ ÇŽø Þ7MÒ¶‰*ù*R<±#ó!EŒGs¤ˆ3=²˜/OÎR±#³âõ,Tž¢eK&0R÷,+ìÈôì¬Û5'FÁ@€/ù„’‘¨¥î¶ƒ¿GßDã¾{­é,/”LALR£S(ÄI3€‰íµÄÄ=”T¿¥Kj 5fGù±¬°#h L𾤆®°a9Ñg¶|%'- : šW2XÈÓ§’JiF Áக, 1™eI Kj Óåe+ØN S„¶ô±˜Ùq™á¦Ê¡ ÇŽÈëW²T<>c+{„òhƒÎ†â!ñ„ÆV—,7ìH¯@-¨Kj4>†£}) ðQ01=5"ØtŠϲŠâ·ðºb€ ŒëE„í¢ìÈdï¨ÚQ³ 2Õ%5ê Ó2ŽDƒX´ßîâˆ&º#ç1;‚A0‚ôvLF•X§+äG¬KÇŽ`ÉlÏåù%XY˜ ÌB”x8.;2éÁ‚X”½–—ÜËÓÞp숆ԣƒvÂÿÃXј͂ƒ ‘m®Ö©Aàà²2ÁlÊ>†cGä­Øÿã·è,§Q¡O0¿’#½¯Ü9xŸ•–’œ÷¥cGà‚‹^§ÔêËM:º™# Ëû&C°#Byø^U¸"KoøëN†Nñ#ØÇ²},ÌÊÅêÀàÈ$·5%U*7‰àˆÍX`=tEh@µ«„cGnõiPˆ+˜#piT¬õe«¡—Üm³RÓh&ºg¸ÇÓ Ù–O( Ì„L†Aþ‚s@!­[±K»ãa/LØ ôSÌ’€pMq%ÔHË}½ýÓ=ÂÈË|TKÇŽ`ñÉ –*Ö8Ê×jÑk‰üX:vDBÜò3rkJTe ±¡…bô¶Y%#Áàð²J×·¶ã#G+¡{·T¨WE¯ßoge¢!&žíÇ;‚îñ­êÑ´­ºWºôýâ®H`"ŒÇa H­:xaî\U…Ãñ?K…¦ê ¥Xüf*ÜH&?±µo.¯›Uð«Û ©¢C°# "bÀÛ«6`a…ºF–=ýŠ5žò ÁŽ´ô´óÒFêWÖ(@Æm:³V:asE,‚¦’é‹)j{©óú蔞P#võÞM®®F O»A58«ê½á±y±#m~Eöš"Ó:šyY­.*_-!ؘ׳:âH¾­r}AVÞ­Þ»ü%šdœñ-+ìÈɶ˼?ÂÏ¡(Œ#GêvÁhr4Âr“‘`CŠØ{ÇúÅræŒb(°wÍfLÐ'â¨}SùZ¨à§Kj ÄÎu¸”TŒ 4Û¹úJ8~঱µAÝa!0(¤R'#Áè‰ôû6äjçÍ+±QB™Ê‚2h!Vw0¾_óÆBB°#B—ÔÀüÛµO¸À ¢©òÉ¡ZuI VèõûäÉØhÒ‹â*+;ò^Ógœœ Bˆe‹Œ°tÜZZ´ìŒ+üä[ŸÂo]ùX[4UÕÎêMõÂÏ_:vä|G#ßt÷JÃKg°`!Ç • 6aØ‘Ÿ‡Û .©YY L…ßñF¾C°# Ž¢%˜Yìy+X(-ÿߟ~‹Ÿ®ÝQ·¢~#/LxÚßßó =áÕñ[{^Áó·®e$ Œ£ º‡`GІ>ûo|Ôs‰EÚØÕÊÊÆ÷;;_¸©@!1åðC ‡Va]½cÕFˆô§ £d$p¤e‚on}FZ‡ìv§b 4çŸ_þ°ÏÝÝ£üí‚Ì\h¡knR“u+ªå½HKÇŽ èîõŸþnAV.|>€N~B°#¿ºv [ B˜¿¦Åþ¯OÐÒV±»×¶>#•ÏÒ±#ï·œ|0üŸXhûk¶ÂC€‚µÜ 'œ‹ ÁŽ åêˆ)B7ˤ½¬Ýò䩳Æ^ ;‚ ægmÝðv²Š6 |ç@ \NFüÉÛjÞEe2ÓÒ©•‹tvŠÆ ³"Åå{×Ǧ&èIE~)Œ#¶`4é`L°£™›Ut²©¼6+-ûY÷ø1’—™ÅÞ=Ô缉¤§F©ûø!…ðTzo&ãìg†&ì<9Ê¡~ë›(;2<9ƱäŒh:† ~sF§'Îņ`G`¿l7fš’’‚fØ:’Âõã ½$ï&Q—%)ìÈÜ,‡kSh&Šéɉi“¨4túÊÂ"Y‡cGœª"œ ¢Q ó!«ú¼Øý;öÀ­$‰I,vD?œ31AŠŒD ²æøbGR•XšØ‘Ô”Yí²ÂŽLÍ̸²k§êô!–;Õ-”ˆ0ZÃ)ñ0SÃ#\´—M4KGéøÝAzÈ¡A[WN]“8 ­#¦ÝR*¸‹Ô·ØL¹ãcD–vD¾.4ªE‘íd§ˆÕ—¡”²)¢ úň¹£ ¶GÅCº¶†“î~8iðJPqtAÁ‰iO´ ÁŽ r™ °Š(/9¢GpFÌ`ö‰#ÆeÀ¸¶fYaGðÕ U42£ŽóC;ya j(У4<1ÊÇýx¨27Œˆ„%™tÞ$¢ï6† ŠbÀ=ž³ô-•X0öFÊ ÙþÄ`G௰ :§Àð24³P Ä#;2>5!/:¡"†K®é‹/;‚šÅ”Y´VåÝÉ…Þ“¡Ó¥cG¤³ˆ5Eûaùи¶&;‚îvƒ1–N kö¾ø¤É>bÀ+ Tw0Îü qmMvD}5Ë'¥-ݫ༰*®B×€qãyç‡DKÇŽËN½†¼‘$Ü”éC2èÍ`¢ìˆ÷‹âë˜M™–c÷ÝÜ숌¯£Ë´p$ü"ƒ"ÌR|½O¥4…cGœè¸V‡>^’oÒk¼? •Ò;´§Â®‰ñpÐKØza§Çê £M›Xùи¶&;"¿²ôI+=äÕIÃö[_X3A­_‘[D@´n3F=«c騑›½,TœÄ’ß·´æ”Õ.;r­ûf,SHn v_OLÆ_NÙæŠuÐÿX>­âáöª ƒ÷yT!Zü6$/4~Hô8bG®ßog»Ÿ§j¨‰=tô^1FL´ÀEã/gÅ+ÅV}Ùš±é ™e„/ %îÅ–¤¢#-=íd/lr WššñÐñjTŽyr‚ÁW2“3ËŠ‡6– !~ˆ†¼ñ*ÆÏé÷-7¥ €HvD^X›õ›âm}]¢°ÕÃ-•ëNµ_a¿?§d°¶¶¤JÎ{v¤­ï.OYª\ÉîÝ`3ƒ+Sî‡`GèÂËpJ;Ý+/,7rQ,+ìÈQTÛ±ª^a²çf?ááúíaù¾2]”ÞÞ× eKý€§­ÞWîhf« y CvA¿OF¡91kŒ&±õª‡]@ý2ˆN1Tyÿ½YsÚJì«Ù*/¬ÁìS¨rª€…`GðG/ %èuRõP¼Â¾{ué¶ËCnåkK«H7~tý4o¨ €Hv$vaz[=îoîi»ãÎ;8âá‡-§DåÕ¤rݰ¢"¨‹¼Ìì3·÷`?·a?vspQΈQ}ÉûæzvÄýJÍ-òUÞiü”5á®êMÒl…`G %´žQ A¦áØ!êÁ¨Êx<>RåüÐÖqèé¹­¢V¼ºYaA êu[·eò…õpìÈ/Õq¹óåÁZ…‡ð®¸o…òÇ%bGP9_­¢kØÏÚI†´é!L vD}Õí|¥÷Œ^hMÝmòõn©¾B°#ô8~¥’äÉò¶1&ad-|?Êš9áLU¬òŠ:RG?¦‡ºk·É|N!Ø‘s2ËÈŸ>÷ûTþ3M‘«i騸HüUz4æ]«m^[“0ìÝšDñ;lgháü×O~¬¿T±;ci/;!Qq4ÍrKÅzr!È¡X!Ö¯ÜE†`G.Üm¾‹îëŸq¢>òí©³à+[‚ѯ 41vä™ jƒ‰ž*› ï€Oˆ…Ч*We ³œm»z¥dr„ʬP÷ÛVÓ©=þ§c^½rêª/«W/1Š„%–¾&µÇ14ª•0÷±Ü½‘HAf™ª¶ÞÎQ;Ço3ÃìúHg•„!“Ú¯²JZ!š…}¤3jÂŽð’ ŠøDôi€ –%;‚èCj§ 0"$‡fíD| ³ó&g¦ÆÑx]CjJ*aAÐ ‘__†~B°#³øJUå“”z$â<”±ï숼² X:2‰=ŒâW:í`GhˆæT¬ÄD0Ù ÂŽðC¢ìˆ!ìdF‚-rÓ³!ŸŒa˜ˆÄŽX^€ÈrƎС¡—€‘Ÿ‰[B1ê”`è$!;‚ Â"’Ø‘2U]Ø  ÄŽðC¢ìÁDø#@à÷<"숆‰ÄpN~ìˆ~Û-Ä;Â0ùÐÒ{!þ;;¢¿ÒGcócG°˜˜™d±Ô0µ‘Ø (‰ Ýâ±#5:½‡Ay, –p†‰Jˆ–Žá¯$vÄY4v-‘©h(ØÃé݇_;²ª°ŒÔ‘ÄŽ`: "ü0ƹˇD!Øȧs…ÀŽX:Í—¡T4î ƎXúa LD>„`WˆÉZ$v„¿’ØK‡·›{Úù6:ÆŽh@Éø#ÂŽÈwô;¢¶— _ìÈå{1˜H vu¢¼ÄŽlÓ±g;²©\½‘釉`1ò‰ù¿3ì„–¶ÄŽäed¯**—©b;bé—Z$vV@‚´üØz(±#`W¥õ†ÄŽ”æÖ–ÄâÖ‹ÄŽà«Mú+‰±ôÑ'—Ov„“![;Ò¨"£Ÿ;‚áâØ3cG ™ÎÅL.vDž³bGø!Qväê½ücG¼‘ÅbG°RHKì,ãe±~—-v&ï¤HÜBØK¿o-nâ{m¬ 숥ó«Kì,;½ +±#ÐÿÕ…+ùJÆŽX:ÌÉõØчª;z¶~ÿñ[Ù 3L$PB´H숂‰èP¨ÄŽ`‹ñô†½ï7Ÿä.3v$ ò ë ÆŽ´>èˆ] ±#2ˆAÅ9ù;B0;r¨v‡DÒ/;²Ó…‰Hìˆ Áލ¯”g2/v„JìÈ~•PD5FbG |àäh{áÁŽ(€tÔçÄŽÀýÐòæÁŽX:dÈeâ‹éõ~Å0‘HãËÇŽ€Å­©$vL9t‹Ç޼¼é0ü4;uƒÎ@4ÆŽÀø6¹f‹°#&ÃŽ`¸8û,»“Ø‘oïPA8;òüÆòla‘ØŽ €¸UrMQÐîÁpÿGÇ/Žþ$/QbG  ¥s¾H숆‰lµ¼Ø (‰Dâ‹a˜ˆÄŽÀÊ?)¬[b°#ú«Xœ•°# PrÉ (‘ìÈ?ˆ„"ŒyWJüØ‘¯oyª8;ßÀ޼¸éPÏPŸ;rñn‹ºbÉûhñØJ(b`G^n8ŒÊy[ÍØ‘ PÒÌ ì‹|L±#«ôe4_;‚_y8.;òp|˜Wñc‡¡ý|ÔØZñÂŽà+ÙZ‹ÃŽDuŠë aGŒýÕÒ±#îëþ_ìDFõ `GêJWõ ÷%±#yÙ(]¬©GñD¾ÊØùÕc‡Ñ_uY'v_]_}.ìVesOÛçÂŽ r<ü¼ØüŠŽöüØ‘ZNñ¯5vÄÒ±Ì8bGΈ¯>/väØÍs¼C\$vUÉK÷‰n¡¯âˆ©bÏd‘ت3^Ø|uB©¯$vda숥"±ò‹Ç޼®¿òcGšºo±#÷y±#ï»WÛ,;bD‰yZ}Ulù°#–~ œŸZìHVz&‰ÁÀŽd§gI¯õKÁŽå8iò?/v$¢Ò·x‚€‰Çޤ¥¦Ñ¯¾všUxø`GTE ÄŽXþ¿¾ªôïÿΚyòŽØò¾¥Ç;"Á‹ÄŽd¤¦¡Án¯“yG¾ v3%1ØŒ!ޏskqØH›®*nØó"›E`Gø"§ÚÇ ;R˜?>51)®§Iæ±>?v„.²IvÄZyGø"¢äùÂwÖbG* ʰ4ü×Ó$;‚qãy_ìH»ºžÆÑÿ‰ÁŽ4õÜâÌŒÁz‰]d³hìÔ`“ðÇ ;¢¯§‰ÅžuÞ‘UEåX› h`ìšqÌ½ÈÆZ\Þ8üO®ßyDØu‘Mí¶£×ÏLÇnq°#'Û.³Ÿ°Ä;k]޺Ȇ?>^yGv¯n€¯¡ìüÌsw®}^ìˆtgõ(±#ó]O³ü±#ЄtŠËq©yGPÌgÍ"±#òΚEbG^Ù|DzkKÌ;R–W俳æÑaGö­ÙJZ”èñÊ;{ 6vKΗˆ1î¬Y8fØ‘š’* †¤àkÏpŸÌW!wDKÇŽ ê£ÄŽÜ¼Ïz*TŽjv?‘0‘µ¥U0Xú"›ÊAF­Â±#­½wÙÆAt±Øñ±õA êð¥Ὂ¥U‡<ƒÁŽ€Zî·[–3ý˜k,=u‘M_,vXSR Måö1;!GH/U¾ž¦­¯“Ââ±#ƒãÃ2B¿IÇ$våkŠ+5Ld‚Z½+É^sO›CÝ#<‘q²¥cGÐXŠ;‚ -ÀJI[:väúƒÛ,ÆØLPZjšaÛU Ñ&æq{Õ†À#Ø0ó¬a e<þqÄŽÜî¿Çb™§j¨±¼ØÆzçc\PÝŠêB•ôk¢©û/̆òµ0I7E›ýØaCyʰ©E=´¢¯uµºêË®,(“'§!Ø,‡[nÝÒG¨–;¢“‘¬å ÃŽ¸)F1vÄMF¢tdƒ[D!Ø‘Ž‡Ý|.‰•E8§fu‘ž5[˜1&—î¶ðB ÄŽ Œ\Ú!Ø‘;»øÔ±#Xqì}aaJI ÁŽ@/ÑR¥?X»&³#ï:¡c5¦åƒ±L$ ÝR±®4·ëH¾‡ !‡¶‘9?v sïêÍÎ1Žz(šxæöU^˜Ðœ0 ¹)F;¢¯»næúÕn8>,ï¢èµÄŽfçïªÞ$a"š2y‘ žHI ÁŽ@$8óºžF÷ñzO;Ï»”¬n€–èaAìˆ Ln®X'ÝÈEbG —HH ´¬ „;Vm<Ñv‰­@ìÆ‹á}(Œ8Ad$–Wa~kÛ³4Høi¤õù°#?»ôéëiÖàãN|T=~fý>鑆`G°l§a"û,/vD'#‰¡!—Žùäæ¹ª$ ÐÛŸ²ºc@ Qb°# <ãM1âÃŽüæî—à óÇìÈ{&ÂØ‘¿ÉH`õ`_Þ!mÔ€]­ù½ý¯]Ò0>!œÓ§­x¡-;e«”‰»Ò^Ûú4T+\™»ë‡¾yQÁD»ÏØLïµáaN!ál anÈLFB‚¹ÐÑtASüج)hr 8Ÿí ŠÛIì~(øìÈÇ7Ïñ6n?©/‰AáÝÕ ;òÔº= |L†‡¿ìHKO»ŒÐÿÉ‘ïZ^ìH¥./±#õe5Ïè¥ýOg~ɇ™‹ÇŽ`“¨ãåÎ@ÿ§'¾gy±#(‰ÁDv$–ŒÄ¶×í”éÒ±#?»ôaç £L;ògÇþ…E‚ ]ý£sïðO~C§1°#D` ÁŽüí©_°[v´Q’Ø‘×w(Ó&a"?<ð­üÌ/©Lâ‹ñÃD,o2’Œhfíãg°Ð¨ËwÖP2‰yqÓ!¬>lÁþê3¹EØËkã;Ÿ“‘èòú6¼ÖTàH†LbGÖn;$à!ØìŽ.|ÿ5ÕÞòKÇŽÀ»øPl:(ňĎT»€¢„aGÞ¸ô>ØÀŽüWg¡©Ø€ú•5\~éØèuz<ÿ5ØøH§(;õuý~»!ßž:‹å¹Mì”C°#zØÄØ‘'Öí ¢¥Î9#N¾Ì)¶oØY‡`Gè`AbGêJW•æÍÎÍb«(±#–Þ;ØX™ÇÐD°Ðàvb~&ÉMÏ¢ £ÄŽg†!ØÙ€#;’M«.,—Øl«i.ð,æ—…±m»•pìætbf’±#üæ6žL~~ìÈœmNs,™^’7°#òÖ ÅŽp\Øš;‚î Ùzìˆz¢"þsY#ìÈìÜÈ3vD•aìH$’Y¦Øª$‰‰'vÄ zOýú‘;b9·Øˆé‰?v‚:çÖOB)sæXz%ÈòË ;"“… %ذá#æ-úÅs# z­4+ÖgFjšB“Ì87ݪFÓ#ZÙÅ4‚Î2¢~¨»FŽbs "`(iݴݪtz’èJ¹Ù\0‰”ƒiYaGPOº Fà«”# —29YI‰´ÈŒf $zÁ’†^ã‡2 Æ9;=ËÖ*;ÖÙ´Ìhj*žÌÆ8F1øUì‡}‰š9c©¬\èþ¡ÃÆXŽI8vdxr”!G4ž7œ˜ ˜4 Þ?¯„¼ŒlÏÐÄ(÷“('kYaG@}cƒ,½g4¬y5ESR õ™âþ <Áh޳A6ÐHŒƒ„vb0'g¦‡cÙbìÒœ"ÌoïèC¶K¹éÙàσçÃ%1 V¢°#ãÓ³A#)±v¿´JÎBvúªG 0iý£¼0Ñe)iKÇŽ@evtB÷‘_Wš’c²tìj–1/­ž¡>Ö X…‚cvÄÒOí÷¨¿s2²àVb@jm»HL\×`lT+ Jñ¼kðs,Ê.n_vÄRq¸n^¡øUqNÁ} >¬,(Ã*à·íAUep¹$GLº\MKÇŽ@†{†bˆš 7µ,·XÑB°#–ŠQuòKs ÑÍžá>À®Ç¹B´0;roèü!º… “mÔ­¨¯›M‚ý¦ãa/mŒU¹8 ÇŽ`äG\MŽu @OY„Àq}Ùj•žÄ‰{©UŠîäffßéïbŽ„éW?t$RZ£cBí"Ž'™ÂÔ†`G°ghë‹åÌÀaeÝê»ËIË4R¤jYËžcÙ×–Tc½ÈL*ØþI3´tì6œ¬CÀq]éjTxÇûªá]¹FU/;Ò1ÐͲË^WZ uÁ§–‹A›Ù†B³a ÎÊ«:jJ*ñQNIž°©ÅV\Þtð8bG0;œ5ê…·NøJ×KH‘Öòr <„ÌsšñÔ”´öâÊ=‰Ñ©*ÊÊk¹ßÎê ú³¶¤ ‹¦ÃÖ·”×á‡×º8×½½¹bôLB°#XP—*ÊÊäj×MF?—ç•Ê& ÃŽ@–8ÏakÕz°¾îd'²éÔ^zÑ!ج‰|ÚVµ?D¯'g´®¶Õ‹Ô˜Pk!,ÀÍ•ë°Ø%”g÷êÉ1;Ò7:ØÜƒ&ÐK‡]·X}­/[#1¦!Ø5Jm—f\ˆ?Ô ¬Ucw+ãö`ªè²¦e…Á(1²ª4§pKå:È* ý‘º]0šR ŸP&ï63$ |ÓÊZXþafZúÞ5[ðCãÚ,aF“Ø:ñÀ¶ÊõЬ¾ œÕnÇåè[+×ÃXŸ¾}Å1ß¶ÒK˜#üŠø!¤û¦ÓíWø‡ûj¶æ W3;ï”ø!ª‚_}²íŠ„¡`¡AÂoÇšš~°fl¿;néS{é'„`Gà´ŸàQµU,O´]â­_ýÊÚ5ÅM’›™³oõæž‘~‰M|rÝnüðƒ–S®wdoT?¬¼p·IÞ±s•ç 9;Ó£•ƒƒ¿ÜY½ .A³@Ñ=_@îwB°#=—4A)ìÐÂH,vhƒsw9F ƒˆ…ÜÖ×ɃÔÔèKÂп§b6N+°¦Ô;®©…¦Ÿ­Ì/‘çÑáØÌ‹|E?„`°ŠFS_öBm–Ž9zã,+@pĘC3 ãùŠxm×Jv;¯DÈù™ û`˜>¼~š-–ž´ò!ØKAšŽº?„èî®n€„wq2§ÌÜçê÷C_É«¦ð„ ÄÑÖVHÑYMbiøÔºÝXgcøNÃ…¾yå£é˜,ÕCö>k»xoÀá·G´¬Pìôû pž^¿b/Õ!E~~ùCæ¸ËÖo½ÈPN(ÿÃÞRväxëüD?\·ã¸…`   !yåcVGߨúLá[WŽŽ¸?„q$€QvÄÒaK>)Ú±ª̇-§Œ,#šäµ­OÃűŸ¼oÍÖÍuXÎlµ¡í1k·v}*Öøö¼*O)C°#X°Œå„±#“înB%Y±úý–“¼´×—?Y·çƃÛòê±ßÝ÷ É1;‚õÂËÒ]èÊÓþÅÖà!8E0·Ý¥ ËøâÆƒ0 ÛFSÿÀkrxƒ€yäP8ptß¼r”oX†î=¼vÇå{7>spf¾³ó%ø*ÿ*âýßÙù¢LX‚§÷“óï± …½(É)úÉùwùt æ¶JïŒÈD­Õ;ú0fl¥Ç¤=Z:vòvÑu¢Ð¬PìÙ•™pEâ÷tB‘??þ¯,ö bR³õW×>iëu<:4I"¬PìÈûÍ'›Ü-¼P| !µÊŸùvÿß§ÿ9Bz±Ð0é¬L ^ ’ã±#Ø€üõ‰Ÿñ›O­ÛÓP±ö½¦¬Là@Buèô$ŸÑØdDÓ;Â?„˜¡ä›—ʾ¶íéóMœ” Kì??ù}p”óòÒ¦Ã0÷°Y|ÄÔPQå#3‘`" 3SŽæÔíøæ¶§e2Ýì¼ ?) © ~tCƒ.S-;öw§~A£Žïï~›»¿9ù öÇàpJ ˜0ìtö„+ò­íÏÂŽ»þ˜ŠÝA÷ÊÝÄÒ±#=…1Õ,‹²òŸ­ßwwÀqr(VHNŽlá|Ø´DýPÿ,ššv¨–|û+ðí©³ØÙɂьÎÎÌÍ.d}Ùj˜°æî6ÅZצ v ŸÊDSS·ºØ‘Y{–ÆÞWi¹ßÎXgxhÝC}*¡ˆz†--ÌÖìÜìE‘ÔF¡0+ûPw»Žê¥)¬Ç}UáË(í¯ojD Éê¢r9A!Øxb„î%€&%7# û,¬YB+ÐÛ‰pÈÑkÂŽÐñûÌìì="…~ #"ƒ±tÀË=ÓŽd¤¥ÃÁ‘Ð&Â=fçaT'F¸( <žãÃplTåMvÄR'„ãlªè<¥#͈â˜å±†`G¦f!\.ĉ ÏMÏÍp¬ZD¢ìHª¾¡-äÆS|ζgEôœ±#nò˜øÊ xvÄÒ—Ý8_¸—–HDA$v»‰¢ÅcGøÛ$v$!v$€™3F1ïlygÚŠvÄÈ2b!¦Ö2ÃŽ€‘‹ÛpÆ\âlP'á¿°e{¨—K×™H,'ˈmŒ9S†…€#ÿ:@ŠˆGHÐ…tÍqÚ¹ìÆù*Å›Q&¥¼+|YaGŒo)M wJr«LÌLÆ.²Í>ædd§èÁîžs3µ|ò¥º™HŒ,#FUPÓdƧ'\|O@±¼Ìl©Íñ#0cr̹D˜2Ÿ¨Aƒd1ºYÍsÓ2ÃŽ`G=£š2'î¢"h§¥_låy¤îð¨âcIvΚ3ǧ·–?©42£éäßèËnÜü4:ï·\w°ýÒ)±…±”ËÕÏaN·‡•(__¶B±#–Ž”Œ É!°ªåŠö R-;biàÂXG§ýp‚½—бô®q—¸º+çR.´pìæŽÏĪlíeæê uÏPƒ“ÀõóÁßpp=C±#èW¿ÈÔ¢9Æ–pY^ )Ø®¡^yù”%Œ)>V­”—ޱt€C€)ÎB›s]Sì·pìÁÉÝO6ÌÜŒPSUîÕ3DáØ|{7–ÅÄÎHM—PË✠c`=ÙhÎkKª¤‚ ÇŽà[u[„Û £ª•)DqÄÖQC¾œ…j«+­Vm"E%jÛØ\Y¡ØKOßว¬ü†¦tÕàœ»sMÁlïí¤V<°#Pkèã¬èã´0‚PªÆ_:v9„NAÊÌmj ÌcÍr@βœb,f.RÂ×ï·³2!·G¢67‰ãlëñÄŽ€®tÝ`7ÕÓG[]=KGöã×E¦8fôb]©s“X:H#M#ÚZ¹úÿò½œ2PéÛâ '!yc…bG@·úîr:K IÑ—-ëän¹n7qüÄ ÙzK"}¿Ê‚²­:„|3vÙW£ØÞ5[$Ð ÅŽà‡:ÀàÈ(Wå¹½oZ¡ØÐÑëgàÃÐoi¿Ï¾j¦·¨ûFO Uc4u’Úw²ŒÄŠeŽSrM]ûëvIŽÁ·2U{¬*M`g8EKÇŽYF ŽPã†4&;b鸴/ð»FEªË—6’®c8všðlGLEÓ+üqwõ&òèŽÝ<Çn^š{ C£Cƒ‡Ø¨¾-DÔ¨ Þ8Å»[cds1wÖ tˆŠ9w'ÁW”‡Єôþ=L˜Z.K¨5q#ªý´{õ Svû²£7ΰˆÂ« `JWÔ1…`G@o]ù˜îU5Ò¸tìœIˆ(Oœ1~tH°#Pƒri«QŒÍãÁµÛ %‚A߸ø¿'Uñ|Á‡yF§§G~…ª‹Åš°xëœdQÇÙy†k2p¿½óyyüŽ‘9E,íËWÅ^n8L.7”<[í4U¹-“¹~së3p_ñC™xÀ¨ º×¸q/;bii—‡34†ì½OË?̺XhvŒ£.牆`G,}¯ËÑfŽôUNF6 °‰øåµcü“’ì™,Vå&YÝ ªLvôÑõ3×)ͧ¦¼Œìaq(úƒ=_ÃvÞþ?ýՔ땡Ìäì4o:tnÚÁŽXZ$ä;y9|´aø½ß ýÅ?œy‹YÈ2ŠcþŠomVÖ¹tì6_wúÍX«2sœ¤ z `°  ðüXi}bÅtAñœÃ„`G°Qb<¥„3GÞ= /ôÍn‰„—æõŠã»×wBRè¯n¹aG,ý>߬m®´47›7iznFŽ?6ϲ:ŒÃô¬éTñýUüÃ'­HŒ"Ú4¦x®¡²§g§¼H ¥’4G³ Ë ;a˜œž2û¨’8¥{û87>=1ç¹UÉÉþ$^£Æîˆª¬HfZº •¡DV<u73%úOƒ c¥k¨JÄ* ÇŽÐí9FÁ ÖZöcî70Æm5Çå‡Aï<›Kzà™ÓS£ScÜGú:(|‹ª ø%_‘m/4‰¯)!Âp‰†±´—àßÂu6œ3k!숥‡>!«Yé™C;Å;¢ë™Ò~•V˜žU•çã숥>Žæm5D bG ½Ã3¶4¯Hb±®1V†íÃÑekØh›ÞÑa8TUP1¹´1Ë}±DyAQøe,.ØK¬ô:c Ÿ¾À§Â±#–­®¡Þ™YØ1'# 9ÃUX;‚öt;WÞÄ49LÄU†K!Zèà´7²™/Ë+28.ˆG4Ɉ€WEA©äˆ=F^4ÈjY^‰¼ñ»©^oÈíÁ8ø¥:;¢9Žw<ì‘n•åÞV#‹aƒ-ó0Ǫ‚²<ßæ$.ØË{së}¥`­˜+NØ8B÷†î+  1bÞëÀ&±ï•oÆÛZýÖWI«±º7xß@£V”‘ë±ÅŽXÚ–u™·ôpU–Ë( LFëƒ>ÃQS\)Ý h‰›½†}A=«‹Ê¥“Œ!íôœVã[”ñGñ#–6@+ƒcy^ÉêbS™';byo®!BëV¬ò…p숥3'µõÝó¾mL, SÕÞ×iÀGÀ#æW&áØK‹Ä­¾»<ªdÙ0AþQ ÇŽXúu®kÝ­Æñ+<¨V?¾¹aG0ª+>â´ k £*• \½wÃpÈWæ—Â`É>¶õu¶;ÑP§*|»¾lT¨äJçõ‡^H4xAÆ$Gè·+ǘP¨ÛjVx”Ö¾¼±‹86TÔùÕW8vÄÒBA5rˆÄq鸥¯úÖòk8n®Xç7áØKû$Í=mBG,½siîi¿7x_z{*÷rõF¹Ð —®tÝžð€°Õ¥3«6F}Û“pìÈ´âx«3–ðL<´]Õ þ¾p숥/Akt“C0m*_ËH;âx¹ózfŠý×îÕ›%Gè³weÆK_s³½ªÞØ‚-ˆÇK-†ú‚ŠÛ±ªÞ¯èâ‚ÇÓ·¯ððÂ<ø8& ;bi#{¾£‰]G4ᶪõ>Ž `Gàžh¿d¼ Pš[´§ºAÚPˆý¹;× g"!óœÑÝ×ÿYzw|°v»\ÚÐKXeƒ‹f+_îÐÚþ]y8v/Þm6à#ØÇ^»CP€ã™ÛW•ÂGŠp/÷Õlñs ÇŽ€#–¼ ÓÒ©2ŽÔ£¹= ÇŽ€Zî·_èh–OЫ÷yøqÁŽX^DsÜ]ÝàW­‰ÄŽÀüøæÙ|DO¶{˜qÿÉC8vÄòÞ\C•aw ‘ž 8~tãŒpÈÕPV®ä«q¼õ‚±×öG¬E`G°ýÿ´õ‚±Í‘}vÃ>y¨WütûU÷ìÅiÜŽU¥¿ø©ÛW øšýDÝ.¿ëŽÁS5a¶ºÊmëf‘DµžÓK;¶jsÓ³ŸßxОŽA’¡ê¸ðÚí[¼Þ<ëÜ\ã/ˆ„_™' ;Bõ¼ÛtÜ@'Ào„úÊóè‡`–ŸY¿OÚP¢p숥=´¯Ÿ28Òm5òɧ·.¨)p„¢ðsŒ vÄÒŽ±¼þÏÒ íÕÍOÊ’0@ï·œ”‰²,½…ùÚæ'üï|†cGà®ró<ÁGøX }„« 7DFþºù„L7bi_î…ý—Ž!Žo]9:ä=…9~q“‡£º€ææYã·O­Û#úønãgÆË!°z/5’éœá÷Âß08Â…~fý^ÉñDÛ%F„Ѐá[”Ù\aâãñ#–F„üüòGÆŽ õ@}£숥õÒÛ×>1NÈÛjˆ‰AÕÍ5;!|¥áˆ ³â„-€ä´+C ;«ö¾­…°#–žì|gfg%v¤¡¼ÎHÈa-„±´ …‡01=%q!ð{ëWÖF½ç*·z; 숺ÖVœúb‡½žFBÄ€éÑtìM¤:6=b¤ yü±cª”çc*ƒïH¿ÄŽàÛò‚Ò"Ÿ‡Ž±´{ Ë2çÄ ú°ÁA7ƒi[n1í-ÎÎ÷{/‰ÄŽÌÎÍ «à‘ëM‰W !9 ,ê,_HtAìÈœ=y!üŒ´ô(m v„âÂîiO ;‰žÙw‰0p„fœ—FTÆÜ”ÀüáØ[—1:ãŽX‹ÀŽXà Ñ=Iàˆ—>7vÄàëÑ”ÕNS…¾—(bE¬È¼µÉp¯TÁ$×F Å¢ä6:Òìæ«Í©J³Õ…‚Ä˲mg¹‰˜«ëß¼‡Ižh§DRGŒÖ­1k ÿq*WE·=©[´Žh¼¾njN…º=!h¹êªæœE«oÆR0U–®Jg ¢‹æÃÇÈ3Žù 6š#_y2_chÙΕZþ2h’dµ±½žn»·»§ç3³ŸÝÏgvþŠýe?½3{ôt÷ôékìVÛ²,ÉÖa]¤HŠ”xßI€qßw¨ýfÆ{Qñòe=R,¨¶^تê!+#ȈȌï‹4 s„å£ÏÙ6Ã%©ˆÇ …œJD†}fnfÎë#öTÖ†¡ƒ˜##ÜU±$ħPdba>¡g'ÛàË\¯Á (Ѭȟ‰ÆgÕ)uS«(t¾V‹HCP Æäh™GUÖõˆ|n¼ À îða‚Ð6ŒjB—µóêÄ_ƒ¡e"´Š%ÃeE-hìŽB)މ`¢"ãú§l®žæ8Kúò`•¾šJ©>¦“ ÒVÌû– ˆÆ¦'h­A?`¸¬CAP'¥và½qIJ}Æpý]G/ñ™)LåÜÂI µª¢†¡ÅÚû´rœNÍ0Øí¯HÚçqLÁÂ2ùí­² Å;:39­ƒ(SVTš´Éê”âèeöVÞ³…#úˆÝ8æubjŠ4B+X ㉆±2 žéªffR) þKT–”[ýTì%ôZ[(N`[GUbÚ4GKXÂÑÛ’C‚Veá8812­u¦Fì•TØ8b•Aì±UC Ūª «úBΗ^¤r/YdǶj&5;ŸžOƓط‘Žw?jÓÇ¢ê’J+GTÅê *ÎZ•ãGÑÕ”Vïƒ2GÌD‘£U«qÇö,“8º¨4›^•Q4ì´‹l1‰XDCØbs}yM#$ahr"¦4¬ÖïÃ_1£)Ó 7ëê÷ãöj³È*ª’ɱ­BˆaßÍ6| qdL!VP¶Õ1ŽÞ©Pyq™]SÓÓc”x³e¨“qV´5¬²ŠZ545†:¡”PÌŠ¢Éäü«ë–[ý=¬ ¾±ÁaÅ1ÑX^³Æá#s¼6pe ð«K¡x+³éU ;ÞÚl¢=ˆ®êª†&ÇÊ’ÅÐ9km©oå+j­@g襛ý”¯±¼vm½èìPª<ía¦õÕ­x0Q{ÿ͉Y×ß "˜‰ %Pþ¥WG‹Ñg4).!’áêuõ+­UÁNµ‹hèŽ,ÀÊ+ýd‘ÁuS“}uˆ¤nip´:«°³ÃÝC#ðÑÇlÅÎu·ÃŸ,‡#TY¿Î­†õÄê€&‡‡ÜTQßTY— ZbÔ*Ò6yŽv¡¡ÆQ^=¯µ˜®ªc@ûäàÕœÌåKcî1Mju/õuŒ{ÎjSUƒÕoW¸ðÞëø@UµË­~û%Õªaüæ ÚV[9ÞîhÿÿúàMÊÚ\Ußָƺ@Ušãþ gF! ÇkœAyòÕÖóØë‹=×ù«që ÔWž,³ÌãÉ®‹hØÌ\ ú ' Z¥—jÃÆÅ66šù ¹ØÍaÜÓRÝŒ@;zÇû¢9΢@Ku£µ4!<ü›Ôa_¬QíÑB…É´"›³TÝ¥ïèBaƒîkÙÜt Í绯Â(` `\êË«³™!™‡i³Â¾[8¶÷߀;ÚÀhEu#ŠY9bi£ \…†òZØ©l%Úþ¡5;¬eÀîÆë™T–”dz·Àqž‰JªZQc-†Ð´Mƒ´µyucuæÖ”ì– µ¡˜µ(ç`YàYß A°Ã¿¨¡¡¢v[Ž(ЙAÛ—[ ]B S…U(œàŽNRr¦+cC÷@!Ì‘ñý«jšìUéd“´1ÔešWe+&‘d…œêºÄÙUµMA ‘—™CQ¶ ‚Ø_¸Ñ7>\¬·ÿ;”ØßNfÑ½Ž¾Ú‰³U´zw¤d~l.“¶Ú×X]¸UtBŽªê³û„¨mf ¾}u6ß^½n71J +I[UœÎ¨Ý—û—òdYy²Äjª`Ó&‡õ¶=¦ßU«µM`Áb0‘šÆ`–%JÐ~ëIÌÁØÌäBz[€Š@¦p"XX´ | uÄ.ŸõDŽŽiºá=ZÏÀžÞÌülzaA#*Š­NiCP ÕÝ EåÅ¥ÖS˜ñÎU²…­ðù3¶Ù2L© Œ\iÍv2‰Vé8ÔE9­m’S1¦ìA@ZµÈœ´Ž_.¤u 3³G0”6ž%oÅ…õ51*V=½@‘hÏÖ¡akü÷ò)"Ÿ Ì‘¹µÇ†áÚèwˆ(p²ƒÜb2_MD~ºìHDEQDEQDEQDEQDEQDEQDEQDEQDÿ:(ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~)ÂŽDQDEQDEQDEQDEQDEQDEQDEQD}~écGÒâ¿1ü/[1Qm,f/–v ¹U…KsUV¦øsza¿X«ZH§¹a¨©ÀÆtATÓT³Ô¶~º¶˜[Uµýó ó ^ã cYªB] ÔMT¢ŠÙÚ¯ªÒL;'VXPäˆ:æUU›ê]¬ Žb–ªæQPšTX€ÿZ9Îy£ŠÚ…ñ`ÔZ˜Kë†èÆ ƒs¤«BûÑÅ4z‡V9âoó󪺠«R­#6;ŸZð/ˆƒc° afn–¿–$Š-wÒ©¹9 ¤@{QaÂ*¨jÞãX/²NPj~ÿG1T€ÚP•µa©ùÔìü}Æ\'’Á2¨dõ¨ª!'ã k±éÔ´ã­Êòd©¥éô´j¼ØB5òq´?(9sós3ó©9Œ½£8ÅÉx‘ufÑËôBLI`ªŠ¤§R3sŠãœš‚Â’DÒº:F§'øsiQqÜ&„¨grvŠ>CfÊŠJ‚e@³S(©Ù;hyqÂÒxÐÈÔ˜ÛH=\VŽh<º©†K/Ÿ’, Ÿ™LyóˆZçõL§PÕæò€VYG§S3ô2S‘,³6~lzBOæX”,±qÄ\OÍNƒ££—_àˆÆ`¸0XGXbè]E²ÔªF§Ç¹•ÅåV €–O¦f ®PK(Pše(&g§'Sî<& UÅåÖ>öñ窒 +G4µaÅÔ*‹c­£JÅm<Ê’ÅVÉA%cÓ“˜&¨ ´ £j| ÔÐä˜÷-½¬¢ÎÚø¡ÉQŒ*}F«Ê’vYíàªjʪ VŽƒ#ô‹±¶´*Xmž›ÖK¢…zªK+‚ ƒ0632Jã ̵UQ`®'f§1À"5AE6301<ãõUUÛeµk¤…º²«ú‚<£an ‹êË«ƒeÀkxj ­ÂAà¡Æ­}œ˜™ŸÖ ¯Êdy¹mð¡pÐMjW2‘h(¯µqœÅ\ϸ‹QOMi¥µXïØ ]YÓ,ƒ êÇpÍb H)Õ•U[Eºcèn¬¨ ®YGé®ñ‘é1è(^Ô‘€Î´ö´\q<¹¬Ò.«×»è£©¢Þª0±´»ÇXV5µËƒe`ƒúÆÑ*,7,1ÔƒQ-´ÙÇk7ùsSe½UK€ã­Ñ~·Y޳¶¾ÅÚø[#}SžÂÄìX'õˆb˜ŒC¶b(38é.4L÷òª+Ç.ÅqÚãXUk« t¥¿“?/¯j´ªh¬ëÁÉQc²¥º1X¼úƆð/Ú_®lCyMPE£Àá^þÚÖ°ÊÚ*pIJ¥Õ™YQ½ÌZìÆpR˜š ¨ue3 ŽCÝüuCãš`8j¸”Ú™„*M7W55xõŒ   Xã¥z][õ*ŠuŽ›–Y8:ÚpôO ÓgÔ¶ª¶ÙZU÷X¿2£ ‡š’Ê&Ûêèí‡T 0ĸ´¨²ZiÓr}àèY«úòLP° „ò<©,ò|8–V5WÖ‹aí\èâ¯[š×Yûˆ4áMPcEU}Îܺ»¯µuË­†¯ö»ëvjm}¡]Ç™)c-þ,301Ò;>€bè#Ì:Ô—UrºFzQJ íÇ–ªÆ }D%7QÙÌ$šWUR„Õô¾ ÌœñiÕ0èg¨8ˆk#ì,«/[W¿ÒÚG¬ÙqÕG5fÀ&ÛA÷ŒöC¯¢1XŒË*ë­Ö ’Ó­Œ{Zs,]Ÿe=^îë@é3ÊXÍ1ªº5Ò?>3×N³âh yFÃPú ó.ðêêš…“_ž,ƒ Z­Vë¥Þëüõþ•›ƒeÀ±½ÿZ…R]Z  µ~üÌ`ÉcgÝOih‰ÕV?-¿Ð{¿î^µ5Xt¡çû PªÙTô‡×OóçMËÖfãx¾ç*}F³V…2cÞÞdyu#dÕZìÈ5Á±i­UK\ìꀉ;X]Û,x©¯Î ˜Â¬×–UÁÔýÈü¡åÀho|EÍ2«Â„Çÿé3Šmij –A%ü ¦X­µ¥Õ˜£`1óáîþ‰‘DA¼ª¤lEuSPabƒpuàÆ€61`‡ÞÁ(X=“3·.`TµnÚ¶|]¥m AÅÿѰ¸âXAµ®G”a£€bÛš×Ë€\ù˜?o[Þ†’Á2ÐH§».ñ×GÖí –A!ð¬`bê˪±1äX¹÷¯|DÐËË7dá8vRp|tÝýVŽçºÛû&†Ð<,üêâòÍM­VŽï^>ÆŸïkÇŠ`(Xdh ˜³ê’rèœê@1ì²Ïv·M¡y ŠcÌ•ã;—Žf8®Ø¬ MM‰¿âÿm«­ÅŽß8?ìm¬ÖÔµ¬©³x˜ ß_ü??¹áAkÈóUφ֔VìZ±)XfxrôBïuü‹¡h€9+¯Ý¶Ü"9Pnß8Ï_ŸÚ°'X´‹=×zDZ À˜C÷n_Þ4µ¨ ê º¦ eàzm´90PªíXÜ“£Øy¡”jÐIÇS]—P•7[RyÿªÍÁÍ# @VaûPþÆÊšeV-wûo@/¡x³P_VeãˆbêSÚimXaµ¡àu®ç*ªÂUaÍn¶é8½G=Õñ¥Íû‚eÐæ7/v(lYe-”!̺A~íÜþ¼gõ6ëòŒÕÐÄ(mâ ÏÁb0ŽÂÁ µ €ªAûw®ØdÝù¾vöŸWï]½½ÖæäÀõGØnRã[›ÖY‹¾vjÀsV±4²ùí¯œy?yë£Ö20= /è¡5;‚e œOߺ ŽØÀ‘€7…ì#¶„{¯co…?¡*X„Õ¦øÔ­KðLP †Åî_µ¥ÂæÀ|põo:ö­½Ïê¡¡ÀÁ«'øë×¶=,ŽG;Î@ñjŽØ•TïÇ€ EU'o^¿pPŽÖc°6,Æ ½WQ[²0QW^³cyÛr›q?bžŸ°qÙÚl›Ž_|‹??²îþz[Á‹è…OËÌÌÍÂ{“ '¹¹ª±¡¼úÁÕÛ¬‡Zÿr"ÃñÑu»‚>!èÄÍ X³°•É2ØÙ²ÑZì½ËõO¸û¨ëšE=çzÚ¡ÆÑB…ÍËZ­Å`ªPŒB+(öØú‚eài¾v’6Mðê¡ß°Ð¬}üÅñ×ùó·v~1XÀQKûÊÙ[íôoÛm-SÕçíѶ4·ni²l¬ â°lûÆuUµ[›×µºÿQç9x_ð¬À¶ãáµ;‚ *9Öy®olLÑAØY«bdÑhu|çþ/Y Ë–>ÃT=i3C°ð´{džà2aKެÜ,†zP ' ‹°‰{`ÕëàtW†#T„Õ8‚~rìUþüô†½Ö]!Öì¥ÞÅ1^´ Wo]eãøæ…Ã=Þ Öºfáìað1hPyLuOܸÐ>p"]/‚€í€ØÛÖ#ôŸ¬nX¶Æª{á[^éëœMÍÍÕ•Ve3|ؼÜî…;Q¦6_ð{­NÎÉ›G´ÓsœUµÍ«j,GÔ°rbV5‚OÕ5ÜK!ÕŠd™Õ—ÐÛ½ž‰ÙI|¨.©D“°Sî áÀo×ËlsížrèðMY–sÇ;;¢(ÏŠêFk¸m*5sK ˘õpo~aì¦çfP˜ŽLëËj‚^(Ö#\¸™¹¶´ÉxãoyŒvµ›ÂX¬(^„½‰õÔqbvŠO9Ê’%ÙbLt¾Dq¬lѹ…¹±éIþj=rL§ÓêD(=Æ£’‚ÂÒD±5@Æ›PüCj=VUAÀ9: ÕsdÛy¥´ Û©0ó‚ŠöÆ ñøÝEiuUM*­âcq[$ÚqÖijW¶Ø7ÕÆŸ­6'¸OÇ4èÀ Pœ$T ;¢`AGíÝbYʸ•y :|n)'ìˆ[…X³UhLÒB¦˜e"kK;iY[Úm±¢é vÄ*ñŽø Ï6PˆW€÷n³ ™†¸»‰5¬ÂÆn˜¢6/P/^Û ØA ‹:m‹£” à@/QZÏŽF`dF55޾bŽFÛ$ Æú@m¼°Ñ¤àé?ZžšŸ5Bc>r(f5(!ÐøB¹{AãutsÁ‘ï@ã'‚ e:53O£‘vÐ;ëNËá%dž«¯éÔl`Tc0WAŽ“©éy¯ ¥EÅÆ:3a¬ƒŽËÁ®[1F•NK…9ˆ[A#ŒrH« ²ž]:šÖÃepD³á‘}¤á Îãö,é3…CŒ®à¨¢ž`(XBŸéðÈÚø¡‰QȆ‡* ŠôÈÔ˜”y¢Ò¢yZQˆ¯j4Šã¦_…­8ƒ!°!74¦&ÐÇ4<¹ 4dT IàZûxS„BëË«½%8MŽûX©ÎåƒÕÉ8aGP xŒ‹ö g!Ž×6b04ù´(Îæý÷ŒðÒV¡/›;ë¨3 (J¶ :ǽ°  £vŒbi+¹Àšm¬¨“Ó401¡ «`î#*¹5ÚïMtÚñô Ê‘4]#}Ó· Û;úh’yÖ úäÈÑãÉå :¦¯|X÷1£O0AجJÁÀ擜l©t0ãÁÃж¦rðű§ p÷ªËqyUƒ¡+ ö7†Ã‚è³±Ð0æÍUõÁ•Ë-¤ËP_0vØtq¸‘ {ãà© i£žàñѹn÷䃱º¶9[€™!& àŽ’pm kÞ?\ðsÖÔ-JõïTÂÑq‚¬!m‚˜¸&û†öjÿñÙLH;8Ñ.F0A$VT70c¹ÊBÌ"ˆ^gÅ8úØŽ?£ªlQáîQi—®o09Bw Ý2ÜB¬ ìÛ=9DâR_µÆK=`ÊSk˜t±÷:Ë1Ë@g^æàAÖŵÁ®)¿Q€{¹¶®Eú'˜‰%"‚¸nl\cø *ÜK‡ãº®¶˜±ÖºF\Ûa cÌ%B‹KnhXÅὨ΄«”XŸÐY§ñÛÃ=l­²à .&Ãð0¡vø$ôÐZûÉÑ™[WX™ƒõøÏчPÜò­Íë¬0Í‘©q^0ÙÚé®Ë#Ç•5Ë‚†ïêÀ.ï<ÈQ”úKRC Ü>Âzž»ÕÎÄ_×Ö¯+ÎDËð¾ % Ò¹B÷´Ñí¤‹ùØ8GƒîbS [|_ËkOܼˆG‡ЖBí¹Ü×!àž.µ¨£asåB^S SUiß™e=ªˆ©ïCÃoG(g>îÑŠš&yЉ¥zªë’á aT·/o“F¹s¨ÛS™ªªK*w´l0„¶ø£Îsüõé{fÍL~ÔqVOPÆI@%¨è‘é'¼qáû)í @6ÜÞÑŽ3üõ‹›–qô14û «l*úwçòçÝ«·Z£‰p9>¼îr¬-­|põ6kU^?Í€B°Ë†zí¬?~ébj>ê<;&ðñŽÚñÅ·4­mºÂ|òæ¥9ÿ–ziÇò Òo?yóbP™@ ìHõ¥ÞëlФà14ê9Ó}eÎï™T&Ëv¯ÚZâ9ð[ÎÞºB¥[5¾U Û ŽŽß¸`x˜ñÂøÎ–A—õ Ž&RuûZÍh"8b]trTr¬_„†èà5úŒziÝéØèW'ÏŸiÝeÅ{a¡hÏ@L¾¾ãI£Tåû펼Áý­÷÷¿ôb{éì±=¸gï‰hâÜ÷´Q.Ü¡k' Ž0ޝÙÜS¼xü þüèú #*9èˆ|¢Ý«¶HϦ«Ìw‚¡÷ÑûZwO~ñq&¶÷xÛnƒ#ôüÁöã¬ßˆ0\PtAðñÛ—>ìãØÞº­Y@“ÿã£ßòç“%Ò¦ÃcWèsCyíSˆ Ë;Ï£ŠÞí_¿á‹b¯÷ÖÅ#üõ»âXÇYÇOðWo{@rü ýD§£êNP™@íœìºHEð×`XO”1ªB“žØð ù€ ýÝùƒ\èö|ͨjpr:Í“–¦ÿÉ {‚Êüï¿ÄŸ¿´yŸ¡mP fP¾¤AÿʼcðÖûW>VÁC~ ˜¿;ô+>~nË~“ã\êÕ³ï³Õ ÂìY³=ž|åÌûÝ£®×§}—-À úïü þŸþk˜ìo¸VMúÊÖÇŒ0\=iô½ƒµ•˜w.ÓÈQßÁïCkïã¯ÐÞï\>:@‘W¯ ú%D}½|úì;¨ÔW·=nE|ÂuD1þúïù–Q{Æ9ú]š/m~DVsMbüûãS뙹Ôï/ n:`õ‚ U8 ì™à¯Ù6ÿï{?ãÏ0VÊÍ‘^i†þãß1 Àüòä[|ÎF#àË[öÍÇÿýîOùó ;ž2^<˜™›}åÌ{7Gz}¿I+_.ˆùø—oòþÞ Õ(…#÷³DpÀ¾°ñ!ã\îðµSG®Ÿ"çMúæÎ/¿Âöùõóp‰Ð;asÿoÿˆ?ÿoO|ß±t&40}†7õ­]vˆ L«V(çàÆê·çží¾b<Ä’|¢-c>úÆ{ö aC“Z׉-¬„P¾°êè34,c¸à“ÿüãß9Þ\ÿïOý‘µñ0£xȪ5˾s¿i†`ò¤ J„mƒ9¢=ÐK—ù”ÀSa°ìA¯é@ûq0¥ÏÖDÿÇËŸ¿ûÀs(_<ñ&úè×%н;ƒÀÜ}¥ÓC9ïpAÇ!bÞÿà“?³ùaÙG%öý­ˆyÑÆ'7ì ¢¾^>ý.9™(Å÷¹~û/]Q†éÊꦇ[ï“6ôÍ ‡±mt㕺$Ttr°Ž\ØAlSÓÚl€u4ŒZÿeC ^îëlïï$vØR×­ÑþËj½àÅmÔË‹K±‰6£fúÖ%.³/Ë\cùZÅÑhÙOgG4ìmY^‡Ï UTƒgÓ©ÙÃÝä/qà©P™6È ±ÝP–Ý›kªëšGžicÁrl"æòtÊlðÅPð.}¶tÇ`4„H¿e:ÊQì ¬ ÛguÚöÎc±‚ªâ²`€Œ·½*•åUgñrµ;GFù…y lZ¬FÂU'ŠB¢´4ü…*.\ÄíL+?gÖ‹îy²ˆD©Ý„ÀŽd ÊK÷8ÄïLÅM0‘!#YƒÎøŽ9&#òi]ø¶Øn¹[,ÂŽh°#ŽÙÚä$-øŠ™afïiÚ¨7Á”!‹‚¡¤V¢«(,Ï—²t3ˆÀ ÇŽàOêÌÈV™Ì‚%=ïŸ1É̆×Â=ˆiÅê5žð%–ªÐx#‡D8vṲfÒ¶ªta×®£Ãe”ge¡aó²ÙLAPÞ¢`G¦RÓAÔ©ô²d±¡,±#”#ØrG‡| …ŽÑpßSQa¼ÄS¼-vdtz"9rôb¬L–ѨÎÍÏ¢’.Çx‚›G™*‚eÒ:ýõQa/¦Ç¬J À)¨.5›·Ô°#`4“EVkK« 뎈ŽúO=J—™°EÁŽ †1;GåqÐ;ãZah,¯3ôj8vDçJN*)Xìˆ ±6iöÂY°#FÞI˜Mãäh©aG°¨o õú—¶»’ ÆWx{9ÈUðÔ˜¨Z¿*ç6{l@€2a!Ъê&Ã(ä ;‚å,JþIgkph‡§Æä¢–„±5<épìˆ~ƒÖ¿-vä@ûqÏôûœ80û[Í3ß;räÚiålø‰퉶Ýäcúþ•ãsw9tóªöz᜛Ã='o^´:@$ …ŽG—-«Ca/RˆUÆIh ¾÷µld_èÝËÇ‚ÐdGÃGžÞ°×Ø^…cG.ô\ãèýíRvÍÐuùÄŽüîüÁà;Žv®žlÛcô1wìª×ΰºUàøìæGŒ‡áجáEû œ4x½zö=â(±#Ä1ÆÇŽ(8H–Mª2¼¾¼aGàX¾|êÛŠZ#³Èm±#o]<,7Œã)‘„FV.Ô}†$ÀÍ7(ˆ¿pßSÄÆñó‡ÌZ4¡ž‡½¥ MŽþEí~ƒ6Üãp숆ƒ|`6JÔ¦Ž ÇŽÌΧ^<þ¦{4á·ìpË¿H?ŽyÿÊÇ2 ¬D¦¼~ñÑë¶Ãå$£ÑáØ‘WϾĽ}{×3ÆF oØøó?;öšÕpÀøÊ¶Ç¸Ïô›e[¿›÷ /Ÿ~÷–×lYâ÷½ÝϧC‹‚ùñÑWÔ©Q àõýÝ_!ލä×¶…†ml\ÃiŠ  ¥³! "aÀ>ò†ÁVè¼$wLÜWìb‚øªpìœ.Ë6G×+cÇŽœënϸp~Ú³zû^ápìÈÌÜìßú¥õôX6ZÞ°#‡®žøÀ«Ä g6ïÛê¹Ç?ÿèwÖó„d<ñ'û¾A§Žð‚þúà‹Öª í ›µ(ØTò3a%ÁŒBAq%¯ÏüM„¶`× ·jQ°#¯œyÏM^b.Ûôww?gl!ñ#ÔGÆA¡L%{¶°z$övÿýúsi‡cG.÷uÐ#`0uüØÊ÷.tc¤'–‰Ÿ{üb± ““7ìvg)yI&ÜêŽHuI¥±ÿ]‚Øl[Ñžé€:2-ä#S(8´±LÏ2Ý„Âd¬ÆÊ-7Êg숣²,›GîyÃŽ¤Õ»¯£úÜžÅÊm`aÌ Ë;qrfÚˆÒçXA¬Ô‹ £´Šd¢´ò‰q´`Di;2ïGljùÿ$+T‘Ü,ø3ÊaG‰ò‡q¼yJû‹Å'‰rtxÌ`± ìžÇ]ìˆSB9¹ƒCè*à,T"q$1K†’0ìˆ~ÏÃåéލ ñÄ»â$M•È×|)ɇf4?¿`6,³§õpapUÓ^b• Çd")—H8vdVÝÏ2ï•zµTB1Ð*Š©ÔL:3æhCš¿*.Ç~¨c®^±‚Ây"##*œ;v]“P›xa|N NãÖ€ìz713•öŽSñ§¡ï ´Ò—U…cGÔÝ+ó<æ ±$ukyÒ—/$;EŸÁ]BN ârŸ\¬‚) :>=‘³Œ’rðaJñ Gžþc|8õNZOY,ʱÏaN2ƒ¬!†Í^RØü\¾,…ñ™™O±èª‹0ü¬Ã±#py9€KZ¡Äæ]αXCY4Z¹cG°¦úƹµ¨dAi*ïj¤‚‚º²Lí´ºc”U’HN‰`€ºÄ/B!Øpìൌ?ÍÍÏqÒ&È­q•;v(9¢ñú®O»×„cGzÇY8 ó'ZsUƒÔäK ;2<™¹—D]O ]W_^C²­+pš;žMüjeÍ2ü›¹%Dä JƒMLY¢ÄÈå ;Ò36ÈX(ˆnIQR‚êZt^Dè¥k]lú1’ :}…V_]Ó$­|8v¤{t€U ~"S}¬¨^&µJ8vêHmP=íaú³Nå ñ…1B°#„há>bfÁš¿B·±´¼aGúÆ{=FpK°s“ú³¡¼ÆØ8å ;‚ÁäµL‹‹%špcãZiC—v¤cð‡-ÑN’cÜp±Ô°#*›HF` çthB¬—W5Ð ²¼„z ;X)9×Ȕԋ‚9'.¡€õ±h¹ûZ6ÂÐ@o¸Ó§A³LO°/ b¼ºŽ9×}eÄãHËY wùÓ5ߣؑ£gXÙÒr÷Ö¬çîÕ[ñ/ÉØX]Y•~oÕm –I#„ Æ=íý s`"ó ïußDlÙ‡×O³EC¿Ø¦_=¸f»´Ú¹cGPÿák'Ù!‡w$sïÁ.ïõÏTîØTþAû f31<9šá˜HRË™8V«4âkëZOðQç¹Ìýe:ŸbÆ¢¥Õq¡ô=±#íý7X/(h¨¨•ùfZëVp˜“èsŽÁÖæˆº !#ç½Ú£ï*¥¶†CìºÈ:$^Çêè—ÄÑͰeo_::çyþx2§öD®n“ódÛƒr#Ž9¡ò—tóoëJ«dh(mp|ëâÞ> ’u]&_ÐYüôFkïê9q3sµ4’ ±è %>­‚Ç7/b« w%ÍŽ_Üô¬*oØØ}V_äæÊ™¼jÓ23;vDçÿ¿Ê¡¸ä=ž¬Ülxt!جý7/æ¯pó°fyÊ«[¯RýŸí¾ÂÞ D5¨¥í™,%N‚Á&ômq£ <¹atVñ#Pƒ‡EÄrÞ.çð^(¥ÂKÞr€q„ô¾ª‘…v…NÀv"ÊツÅÈ_ñ+’FèÞC‚#”m»ŽÁÐááöåmÓzýü¡^O{è‰Ò^¡L^Øñü[8±¿ÔmÐô®¬^Ö­8º»B4Ò„cG~wîÖW¤á‡Dâ ¶tVñ#p½NxùKŠ ðm®ôg<[,Þu~?9;Õýk‚ïºEg_i­[€+|ü†ë®&àÒË»÷¯Ûe¨ýìÌñ«gßç¯ø!Üx>mÃWã^ª¼aGÞÕÙDÒ^›«ê%’ì+[…“?;—úé±×¼Ö¦¡âfægùZHÑ÷xÎÑÚ;—3K{CÃj¹€ù°ÈPâ,v^+÷0[l .„SA¡Ó—N½ÍW!T$KëÊ«iB¬¿¿ûËØÀùÿÑÑWØcû‰Í‚<Úúö®g$ë¼aGàið]{Ø ­­[! „Ø›Èò!ؘ‰Ÿ~ô…a‚–P}ô †¡ ÇŽüÝá_ñމ¬›!´ó‡{¿.÷/áØ‘×ÏÀö¿…–s¯ÁÒ¯ÏØXå;‚ËÿàÅiOÐ*çeË€0Æ-oج2l) Ÿ(,ľ²b„ë„í–;Í¥†³ sÀA‘êÒ :ø¢î@«Ó Dù©Ô4Mv\Åéz¾\ ɊꦤŽDÜîM; ôëҢ♔Žèº…-þ³š¼aG&f§¼Œ¼*üœÌÈTûƒ²Ü±#3s)öîЪ‚leÐô›¥æ8p¦ç(mŒâÂt5×\XPHa‚˜û«‚D õ@ŽØ‘ÍÁm˜9 zCP4Ý/óìC˜—™,v$²|én°#1÷CZ> ‚OèÑ‚8¢àþ#ìYð û„¡Fê‘ܱ#hƒ€>¤QÄEâ ”ôЕQÜ,<Vd¤ ÁޏIG<„IÍÍñÀRê/éˆ*GH&ɬa|ùúž*¬ÉyÑTè)|õ¢ÝŠERë)‘ƒHHõŽ‘Qg´gçgy cNAq¢È€³A9¢w*R&ÈS4^ÿÐ:C£µì£º®E¬Öܱ#2鈶@E„&a)4^æÁŽ ƒbðcÅ¥tSL¦ñ‰byQv?Ÿä…EHºHž‡K¦ ǎȤ#„_‰í¨*.Ç(a‡ ˜hùCÌú;9;-ÛŒbênqOeÜšå™U†0žÌ IÒJ„ då’ŽȤ#xŽ¿úÑ$éÚÒjt ÁŽIGà@`X'GHÈÓúªBÙÂܱ#FÒ‘¦ÊzMB©G0à3Þ²*I$ÑGüP7Õ-Ö\éÛá‡`G –#™@{ 1\zëåVU[Z%=¡Ü±#2é!EÀQµ£…%>ŽY±#p§ºEú¦Ê:TØ3:À Ë¿ZÌÂRÃŽt vó ­-«BïzEîL60ø*gµ~ ÃË}¬S?,—IGÐŒ*Xw‰·‹°3”©GòƒAïÚû3²hÖ×­Ñ>y-%dó+G±7Ư 4‰‘z$;b$Y®Ó$v‰›bðUž…cG® v)Ið‚ÐÐtO9ýš°­Ñw.‚‘IG)i”©wÔ#yÃŽ\ê½>›‰C(¤H¯¾è—›j`òƒÁª—Ç£ÔæK}×y‹b”_RØXUh_[ׂý6ÃGÊ’¥Æ½K ;r¶»o«Á8¯¬i‚Htu³•ß½j‹‘t„"Mb¤É;‚¥zZÈÞ¶æõ0@xâ™ût}yMkÝ 7éˆãºÛ–·á‡r:ŒÔ#!Ø!Ö÷óû‚ªØ:©GîE숑td¯QÜyžûØZßÍq`,ÆÓ$ÏŽw¯Þ†MÇ!}HJ͆|b…ží¾Â?¤Ô#¾¤#*4{?lÙGg™£‘z$wì¦Xëf¡‘¬Û…râÆ¶¡Fê‘ܱ#2é6P¯½9ºàèKÁ!®”t„Fl¥¾ËFÜM£šúØúðÃ#â‡{Voƒ}?yó¢~Ký²¹Ê—z$;"’Ž(½ÔZ¿¢cèOG0õÈç;‚‘Ôæ^IìÅý+7Cz?î<Ç ó‰¶Ýñ‚¸|µwÇò6˜rüÝ6J=¢“Ž\r¼œ>_Þú(lÙûW>â­ÜŽ– Rù„`GðC'ÀmÅ«¶6UÔaxGý Ëg÷ª­BÀ÷ûÒæ} Û!Ð$”zD&A É0UgDdå«Û—ÂB`uÇì ›BÍïhBÚ^¹Ðò†‘IG)b IŒ`mîØ‘—O¿Ãn”܉&)M$Ÿõ^)& ÁŽÈ¤#xàG“¤ŸÞø”ÏK§2ðˆàÁ«Ç»†Ý-4§Ü ÁŽ@K°¦ Š&1ÞÊÍvÛ½O¼Éç*û×íÂBà b󭇌î‡cG^;û>kohB>ˆ¢Ôœß{à9#éˆFŠÔzhÕJ=r¡çê1oïzŠN¢0e(‰'¬é.ì>RÊ$M'`xåÌ{üCŒ3T®D“Pê‘cgi¯‘Ö§pßSøáoμË?4R„`GñÃÓ™~eÛcåÉH/ûÉ›šZÁ­p숀/8øüØYv§ƒ©GB°#2éÚ³›Ñh’·O™Pê‘}…7 ^ ~o]8Ìðx~Ç’cväMõCw¡ÁGÂth#õH~°#³*§Å¯¹×XÅpo^?ÿëìû0ÝX8‡®ºaø¢Âøí}^£I^e´Íã:õˆL:‚¯xçcÛ ?{䛲a¹cG~qüug¬RûZwBñrl»(žøã‡^€A‘êè[»¾s@hbM©GtÒ‘³4Ø,ÿÁ¯ö«þŽh¤Év䯾8빯h¤È& ¦ ÁŽ@Ïõ¸›ˆ–*…qÑ$žÞƒ“ö(;s,uÍËO޽ÊgŒÐ–Ò¹ ÇŽü_ BHL:o‚©Gòƒ3öÎå£46Øþ‡G¿‹}Äß|ð"Sê™t*ª+îÏ¢áçÿé©?4’ŽRD¢IàCJ¿"wì,Ô?è¥MDH‰&¡Ô#2évy˜GõÃÃ/±j¤É;òæÅÃ|iZcyíú:8Bsz£åüð¡d@=;¢“޼æÁb¦S¼üÓ‡/Ó V±X ¾1æôó‡ ö‚$À¢Aìî.m‹ûÖ®gê…«‚é¼õÖ¥#. ]Û­0s°qt8çØÈÀ„ß«Ž.ßþ© {ÐGº3‹b†““ìö¤`äx`‹íË×c±CE+ÖºN(Fé_-5ìú5=—¢ Œ/ ÷ :2 î ZJ:âxYaVè±?šJÍÒÐU$Ëè¬U8ô#ì…!á°h ùáåÉXVQ͵Šü`GÔA®wá E©°¹˜JMÓd¹cGôË<îrÇò¯¨‚§úŒ)Ž%‰äü¼>BqÛ\R¤ÎêgÄÝ4 Æ®dA„ƒÑ}…&™Ÿã¸¬‘z$wìÈ|:“5£ ?Fñ8îNÌCŠh·˜ }®DŠÈÜ$|‘M»çâcìàÄK•ì„YJBk} ̇¼žÆÑHt‡3ø"›j/1Ã=’GÛ!بAy8Å×!ÿ¿Dd˜?;rAD»[ª±Tgà#ƒÃ€ÈI‚éºÅS¡"t×Õ›,iõ*‹‰|õ3Ø,:~¡ÍQò¶5 ¼ì#ö™Òjç;‘ॠ'¤zÁ°3ð•¯È/)ì ÁeÙ®/yéäµöD–v„@ëVbõAt%Šbcãê™ù”D>ÑñG×H/§1€ÐJIË;‚Ñ–/‹ïÑc”÷îO£üæe­çzÚ]e’V§ðtåÊÑŽ³ìÈ‘ìˆþSw.YDórm°‹U4ì‘ì㽈Áò©Ö%Ëëi)rèêI¶/|‘Íû"t !§:žÁxxí}p;ƒH|å°:_dsR#?è!æFq¿uîØ Q¿í†0ß·B½zâÆ6¬ª|]¦|îØ‘;3jR×Ê(1þðúi^˜ktN‘ß{¡Í´@Ø8ÿõ4JÈñD*º—áêÀ V°Õ¥•òä4;‚|G€ñ+Ø}”?Ö™Yï´î’VþsŽyãü¡9/+'~N5¼vö}^˜{W«PÍáë§ø'_Øø6 )Âxµ´óÜÖýПڪªcA];ɯ†CȘnvÎŒN`à¶â™MûÀQ]OÓwÝHi¤ˆB“xŠ/²ù@!?\ް M䪠Æ!®Ðöo]Ì$ºÀB–‘ìÈÁöã@jDêŽC€riç;'G†Ðö«jà\½/Êc ¥·–#vŠè­‹GXH ô°´ûdùtúþÈ\vä ‡Y7Boѯwÿs¦|³†Ô»"À³[öC™Ã’lÏD…È\vä—'ßâí Å*~.b´O¨ò™U~°#p韫|cçÓ‰ÂL[@ˆ½Œw†cG~zìUþ¼wÍhcx­>¤È†½Ø£½w93ÅßÓQ(Ø80¥%ƒA~~Ç“o^8Ôã9«­u+ÈîCs² ÝŽÿÿX¥Lp‰Ð$°ƒo^8ÌÇ¡_Þú(4¤ äÿÁ¯8Þõ4ôÆñ‹›b4IZëÒ}ziÿˉ7ùüAfæwB±#纯²ö†çü -Æp€OzéCà–?£_Ê' ÁŽÀº)pGXSp°á,I•þÝÝÏÉÃÉìȯO½=èÙ‹ûZ6îÔVûïÿÊñ´2Üà×Î`‘€„ã 8J•þǾî ÁŽ@ÂÙ@Cw‘¿÷·‡~É |…Ÿ“/ìÜ~‚Q/1àEñ„¸žFýÑÞ¯½£s“Ð¾Èæ7R$­ÁÖÐäuðŸ¹fB“ŒÍLþôhf-|uÛcrË;vä/üBÿW 9¦X' ñ]OƒYƒö¦¨-ÑŸïÿ¶£ìDˆµÎ)òE,O½¿PÏ4šDùB?úðe¾sšPbóƒÁvã¼Ì6ôë ‚=e"úSïV¢ìÈÏŽ½Ö7áêR…ÑÆ}÷',äðèd†ìaAè3L%ž)dÀT‡”´ì¶BÒBýP犀Kóº¸ëêõDòƒn9Û}…Æ•Ï`!sy,Ì'Úü?ßúGþ‰B“4¯ƒOò7Ý…™VH‘/ÎÌ¥^:•™âÿ¤± ÐÆ¬Ñå?Ý—AVåŽåzUhªÿüô÷z·<Œòö>¯Ñ$îmkózºÈš“í‹É;ò“c¯2ÇVn¡MÄ_üþGœWþ©{åB ÁŽPÝ?NaõÊ’ò?ÓˆÅNÉ¢b±$í[;¿Žýãn2È0íî½…©¢ O¶í‘®cvDe¢ºyªÂîàkÛŸp´Ú©úðr‡ËYÈérÛšÛhïL. E70nRä;Â@H<ºþ~l¢ÕË}T']fÊå—vDßÔì‡0ÎÅeôŽœ‹÷ˆ9+«›ææè茰#t¸7¨uGiè`àPŒÎ¨ ;‚–ƒŠ‡ ‰éÓ#K°#ó ØT2Œ(@¦Y»7d9bGÒ ³Ó\]‰ŽiÎ/ÌO§f½âÊÕQÚ9ú^‹Q}díÎG4ä'G P’ÖÕú"wˆYQÓôm÷1 6G`GþË;?v¼à.cGþéÈËú´YÅ¥‚Qy§†»©* /é«ÍØâ9á/ÑæÁ1²`G¶6­Û"<™ü`G l);-žÔþö€Ø®zUÀS.¿¤°#êU4•ÄÔ ¯®m.Õçùž«;2•š¦=H6숣÷k;ÂgÚ˜ôi-™Ÿv„ÒØ‡cGŒYŽØ‘yü ãà}¥I1°#ÅñäÜœVvÄÒêà¯{ñ§DUV쇧¹¿‹ˆ)T@‘˜ãÇŽÄäM&ùÂŽ¤ù—Ï/å;’vÌbv„Æå“bGRó©LµwЉkìýê³ÄŽ ZníbG@D¼spoaG4@äcG8ÅÈ"bGíLdÞvÄÑ> Û0玱#5% AybGtŠ‘„³¨Ø‘‰™)-ÒŸ:v„RŒ8w…HTøîø¸{ìH‘ ’ì ËsÌ\°#Ž—Œ„èžÃŽ üÐÔ¯â;ÄŽ`ôH¨>sìíøë`G t¨ºˆØ 1“‘…`G&U ý§¼`GPX äç;ÒÞƒué=‡Ñʬâ{ ;@þiibGtŠ‘µŽ ;rD„l?m숣2ùó¿ìHÇà->— bG𕬰q´Bs–6v„SŒ|¶ØÆÃ vŸe¼ÓÀŽàWtHaGòn¡?ØGg´÷'ÂŽ@ìY™|ªØ‘6bÄ `Gððƒ«™&Ÿ6vĈ|†ØGg×>$Z\ìårX\ìÈ»—y»Ú;ÅŽ‘;ÄŽpŠ‘Ï;¢ÿtyQ°#úO™Ì:Ÿ;‚ßê ƒ>v•㡸f莰#ârlØ‘}øîò§ý¡ˆÜ9v„þ´¸Ø‘×Îèñ|à;ÄŽ<»åYíbGøOŸ9vDýI[í;ÇŽÜ¿rÓýÚ¥ÿ̱#*ňû§;ÅŽ€ûó:UÀ=Šùbdq±#!‘?½xâ ¹µùW¡#Î]aG`æfæfƒØˆÈ‡D‹‹±ûÁÞ¯9K;"ÿôicG-VìȯN¾¥—ö'ÃŽ@ùwõ"ì¶¥tPð™cGÚûoè½ç=‰ñN?v$™H’àÝv•K¯õ3ÁŽÔ”UÆ –vDG“>v¤ègŽqÎ#ÂŽä“òwĉ°#å‚™Kñ@DyGþUbG0§zYDìˆy‘ÍcGî"ïS M㽈©H–‘¬."vÄ»ÈæSÇŽ@©†Ï6ïHþ±#¹>çØ¬ãzçvØ‘º²*ÕÏ;¢¯§毟UÞ‘»Ãލëir‘ìH”w$Ê;Bå¡Ïw‡9qó¼ëÓ~úؾȆèsŽI&Š(kz„¹ë¼#N„¹×°#÷DÞ‘lØ‘<çØï“õ9É;òµmcÿø™çù¦‡¤ŽºCìȾÖtQæ¿&숓CÞ­^ïŸ;+µðI±#P¶|úlóŽ$ rèî;‚_&;òÏÇ_çó½O5ï_Os/bG¶5¯£ÊîEì aîQìÈîù¶'‹‹ùû#/MMdFyG2Ê`G`•¾¤o׺óŽ`ûöïù¦³4°#K$ïíO~êyGèÒ:g `G0ŒäöߋؑéÔŒ>sþØ‘‚‚Âuú/Ê;’+vdaná“æ)ŒÇ—v$Ê;òYÑÝcG$¶ãα#wzgÿ‡AìˆÖŸvõÅ ”KìZ……a…‰X%D¹cGfyf¹³Ob~ìö]zœ}Ø‘âx?ç 2Ø(;Pr÷Ø‘âD« çX5aGôMZ>˜ˆ£Á¢Æ( æªârØ ™m5à¹DŠ`l)(È}$4 úHÇÙôÛŠd)Ú645ʲ„_#&Ñ=½Ò*Â8A^RØpá(Qq¼}Ä ˆËzÒ5¥UÒx‡`G Hü²2VqmiúŽÎÒirZã*d sÇŽàçDÇ ¢só‰!¢¡;hdÿÄ0ËR™¾Ú¶_÷чeõR¯†`GÆÄ 4b±WÁ¢î`‘«.©”}Ì;y—UÔ#Ç ©…2z‚™ñaAÔv+Oxabpd$`IaG£âÏpO1ÎÃ))]QÓ„±bäz·²fþ½9ÒËJH‘ž±>_†DaQàÆˆ—l#­öÕrÞóƒµ÷gÌÍ•õX_X¼ÜGBŠèô$n!*t’r}¨{ÎrtGjÅìÖ…LÁ‚*ìšãÁ‘ç_áØ‘kƒ]œA C„9ÂtHÙ–';‚ âQB“ÖÖµÀö]ñ{ŒC…PùÁލ6w_e— #qÆð2€ ÞΦ&ß>3?جz±¾T›¡/õu°Ð±&K;§E¾'й†¹9Üà ¹,YÚ&™K ;r¶»}ÊS&ç•5MX¡Wú:ÙÊï^µ G¸„ ‚”^îë¹d°6w쬀\_¬Ü ¿ë\ÏUÏb¦ëËkZëVt Þêë'FhÒ¶åm˜Ž£"³¹©UîÌC°#B¬/Ñë­ÐÉ'».²¦…>—§K÷"vQ_Q¬ãI}ü¸ó<{2„Á8pÈú³µ~XŸêʤµß½z~xHzR³·4µÂ”·÷ßàl1„ÁW†ßAÒ©ßGgÙæ¶Ö¯”‡é¹cG0Åê¨N7 çU[àÂh¨qišsÇŽ@û±qGH;x½wùؾ¼ âŠ)&…–ÖZÿ‡Šªã© {°–\?ÍO[ÿ ¡kÒNsUýf¡ÒC°# w.å^oh\µ²¦¹cè«ÔLI¿™>çØŒ¤ö]¡‚ê€:Øþ1/Ì'ÚvÇ â™QÒh&¬—kžÍÅ6aÿº]m¬ÕÆnÏ~¬:|í$o1P9½ûH‚™JM¿¥Bn+ð',4hcesõ3BŠ(4‰†‡Æ{týðŽÞ½ü~NïkÙmðîåc¬Ž4šd=¬ŒœÐ/m~Dî°B°#z®]ô° PG·íÇ×ξïxm…i“ê.?ØG‡ÕyÇ„¥a€Øó2Aïd°ÖÉ;âè˜+¿óƒ ‚μÜ×yÒS˜¥‰ä³cÄ‚–`D&êyxí}“³S¯f„6ýôF•PäŸg±(wnÌ¥^W„` HFvä@ûq¶ÂpTvêìG¯Ÿÿ€  *éøå;“¤BÔÞÚ{rÃ8'wžcõÕPQKq5¢pìÄ’µ7Ü~,[˜ 9¡ßÜùøŠÆí'P€‡®žÔέjÌ7& [b;žÛ²|mJ4ž°U%4 8bõñqè÷ü 4ä+"ŸÄ·ï¦¨0¥Í¡PÔƒÉ=Öq–|¡´æø•­‚£ÞÇ×ï– -;¢± ™™ýÎ_G(aÆwb±ÈˆTvÄQˆœ×~ñdÛƒh”Þ‡žý‚gNq˜B°#˜;ŽG¢2…$ä$*¡HiÕßþ‹ÊÀWQ±Ã®ãk¤C°#o^8Ìèd8´{×lœù•'{×3r/ìzý³c¯q¯1×pé!„§=Ç"MR[Vùû¾0;—zñÄãÞÑ"Äf[óz;!dlêÁtÃ1VˆOȡǤ= ÁŽ`é±g‚6üpï×áoSÞ+¿}okbÅŽ  2U ä jºë¸tF“þ§Ý_–}ÌvúÿËGil`Âþíƒ_ESÿé×٭‚&„nÿ§#/óî{×Juµ ö³/z›žàçÿñ±ïà‡˜G®ù÷|¦ýtYú¹cG`¡þáȯùëŸ=òMìò~yò-¸ ôd}ÃJˆ4áG¼[_mó<šú_Þþ1{¡/Ü÷”7?Ÿ¹”GAá|¡Çܱ#èš¿¡¹H»‹ µŠAw&¼ˆKZµÄ!¡w †"F5;âècÎÔBà$©[±…–ö#;‚Qšö÷‘7çŽHÓ¨ŽNÏgÒÀ˜÷UÀbÆ1˜ìRÓø ×LkÙ¨Öù©Ô´sˆSfÓêܳÄéXRØJ)&Ÿ)Àº°ºÄo׳cGð+™Å„¦Ì[J DÓPV#E"w즣o|0ÃQ÷‹#èào 3‹ žòe£_V%‰bC„B°#˜ý¿€,á %VqôJoôÃPrÇŽ`ej LN±¬Bt›ý‹숣㩬ÜÈ7’¢ ŸO²^jØlŸ8Ê‹Õi÷_U]Z 3Á” 0t“ƒ—Ž>VÃ0ºåÕâŒvÕ ŸŒCŸü`G‡£õ$Ì \žux‚>^èbƒX¤§Œ§#³¶n¹´ò!ØGmé{8:âj&KÆA®¸pìÔ‘’UO»a”(K}…l‚!ô=Åoe&*È­KËv¤ol°WÜó©“„½Ÿ±qÊvÄуÉj‹«¨0.ׯekäû‹K ;âè[?8lI¸Cy™dCF(—vöBÂÚPCïØ€Þ*‚Y«oý¸Ðsmô6| )9×ÈDG¹cGXbÕëÛ!Q¡›–)PÖ”;}šQ}y ¤QþÊ€„`G`ï‹Ò˜ÉyÄLIûr/bGæ°æ ¿‚š°wÏ;Wn‚å‚Ê='Ò‡`µj­»<õ½6ê< BQá­L†L‰ÅǯŸžñ/ûÞøÕƒk¶K÷8wì,ݱγìCÅÉÔ}àµwíÉ1wì8~ ^ †ž;™*ìA µÑ¥'iİZ!]<2Í*a‰Ê1päúiñÛ"¬}6 øå.>„y…cGÚûoleK[¦éj­[!“99Ÿ{ì„\wÜ…“AbŸvYWQèåd×EÖ!ñ‚øšºå2ïÔŽåm-ÕË`ËÞ¾ttÎóüéppT ÅŸl{PndB°#ŽNXÂ/[ã·MunpE×~_ËF8EàøÖÅ#¼}¨p|zÃp„¿tâf&Õ iûÀMþ”!ÿ!بÙ7ŒšÏs5b¦ø‰¶Ý²yÃŽÀ—0|3©—`e C“;vÚòœàßLba7/[KK›);ð®€ÁƒÅ“TW]ýØúÝŽ^_ìæarÛV©„Ož H´5úä?;‚MèÛ"a Ô8žŽ5Â,?ØGã ú¼ ËJ&?Û³f»Œ‡cG eN‘mÍëáŸpQ­¸7/î—ñBÓ# í —R" °dàrÈ yÏmÝgUBL­l;‡»ùð@!ŽºzæçeôsTô…M-Ó)«M/~ vCž®GCC°# O¼É^14<ìK§XÏlÚ·LøÉáØ¸^'¼„%ø3´î•þŒ&„Ê” N(v¾®D@™ôŒöÓÙWZ,žÕ/”¿å#µbá‡ËçÇ{å;âèô!ìù£PѧÅ.ì±õàÉì\JwÒœ³–Ê$ ß{๢xÚ;"AÑý+6Ã9ä>¢¨É:wìÈÑŽ³:±™{Œ-öµÁ›|µAƒBuõÌÛ·DÎB0¢=ã„𛈩ä=®Rã_¥uí 6 ßð«’uÞ°#ð4>ßËÖJsó JâsQB°#p$þåä›üumÝŠ›#=j¸.;‚ÅòÒé·É¢)pFY4ásÊ+K–ôŒ ¼uራV,{±ùÒõI»éää;â¨ÝÄ%‚EÕ’(,„9¸1ÜËuBéIs¼Ô°#°8Ýc0€¢#Sê™Ò!-M¶>¤Mêù" ˆ{ÔŒ¹èêvé#¯Ô|jvnŽæ1QPØâ?«ÉvÞ÷n•*Rœ ©Æd¹cG¦çf3a 'VXXˆ¯1O úE}¥MÍpTžbë¢Q¬ãÂê"‹¹L±  Êļ_% }’;vdÁÖ/ðç§@/èî•TϽAW؉(ÐuþaG‹ò‡‘“´à+æû GzÒ&ÈÄ+—6/¬q ;"BþŠãFÇc\§L=b…Þå“p숛zÄVÚ/t cu-xñ]ƒ(Å}–`n¹ã%ñ¿ÀñÝ`㥎ÁpéÃqKU*ÅH<É•Hí`4ž9êÔ#ó²ÙLFÒg1°#ŽÖãAq¥ïØBó‚qDê‘àXIGœÛaG4dʱ,‡(8·ÃŽ w£3Ö%‰ñ¬L–ѨΩke&ƒe/é}–©G|\ôØé>ªd$ÓcvŽúæ9c—vÄÑ™-²ÉjµÊ0æ³숣BSòÒ%AéÒ¢’òÀ J9bG¨’ñ,óˆ’\¸w|p~a!PDÕÚX^kvvÄñ§1ªª*./ó7/w숣sÛNÚGUyÒÆR ÇŽ©G$aÍg¾K ;Ãqc¨×¯Ì•–ë4*Ž °”D)Fèó­Ñþ錪ÌÀ%}Õ±ûÈv+Q”üS¼0Î>±pÄRHGhêÊ|¤p숆ƒô86Bá•–ÂY±#޾÷‡õƒA­õ+ Í‚qÔõÈ—$L!ØyÃŽ@\ê½>Ÿ*åê´5®.ô;iyÃŽ@¨²Í#ÄÕˆñ/5ìô­LË! ¦a‹?¸²Ô°#ŽNÌôˆõöåmäCÂppäÏ Šd™‘’gQ°#FêI5¥m î€`ͪµcÛä`Í6øB8vËPžJB=†˜Ý‹ØGß4$s59ç4Í\Oãø/²á‚ôˆYIXØ£×O[·Uðø!»Mûþv†®Ë;âè R×J’*\ç/œ3vÄQšùªÀÈú†dsS+y£‘‰™àìkÝIÇLþ‹l|e«K*ï÷‡¬Â±#àxàÊÇ´¨¼ö¯ÛE©:™>çØБk§•³á'´½«·Sá©Ô´ŒµK‚ËÄgЗz;.÷]·®Ž¶†Um~}ŽÑ©GŽ8AJg®§q´-àÜf_˜¶ o^8Ìp[ƒžÚ°×pcB°#ŽvdtJ´ËL:âä;/ôwçZw…pážÙ´ÏpärÇŽ¨„+çdãø¬?•‹ŠqtÜ"Ûà1¯0¶TX­Ä13×úS0鈊q’…ãªp­Y8/Ø•zäÔ;¶ß™IGœÛaG}ßÜÝËòüö'ȳE%X6†i¸¬Oo|ˆ¾ë<«²ÊÛˆ’ŽÐg™zDðM' â/Ü÷¡áʾqþY‹&J¶OŸá`¡ùµûíáµ÷Ú5;Ò9ÔP_nUFÒçvØ‘ÙùÔ‹Çßt±~Ë^ä½.ˇ`G@XA=â^WY#V†¯ûÒÉ·åûTLÁ¤#N(vÄÑ÷CÉ7[$ ç ;B©G¬†¦ážæA%žé7Ë¢mìäÿ䨫™#&Áïî~®Â¿ÙÉ;⸩G&‚çªEñÄ·v~‘@¨ä×^Ii–Ãz¤¯¿¿øá…^ûàɶ=Ʀ#oØ‘™¹Ô?yI¯è#Öˆq‚q"ñÊae,…³`GêƒîkÙ(/¿pn‡ÁæëïÄýM’0ƒüÐ ÆÃü`Gt%'>(@I(ü°ç ýÍÁåË'’þdßЉ4ÃA‚„ša³;‚J~&Ì¢¤•¢0ô’O£ŽÑçƒ[¯˜~ÿ[rœ™› †«U…‰*FžoÏ‘#‹cP¡, v§TNŸT/ r ÇŽ Ùà%½av‚ †pìõn&}h•$Š  ÇŽ¸HW‰z;3h°ÇAàÚVž,É`¹Ò鱙ɠäH| õcäˆ2ÆæßYzØ —ÌÂÂDï ñ#ŽöH‚£ ŽAaQ°#Ð3Ó£ÁõˆÍgUIc¡0J®û")VAÀŒß†cG´'ˆ¦‹ÉàÁý¢`G(½Jð\µ´¨¤60háØ†+ˆ}ÁÕ—×^ÚRÃŽ8Zf'F…ÕSŠÕ oUVØ7>Da›+ëyic{Æ‚a¡š 4$oØGË ¿²ÀÑì–êF ŒÀ­‘¾)/?ÖcSEaâñ#Žvփ߉åU †(Þ;Ièì^(LePñ#ó*ãâ­ 2A=Í•æ‘\Þ°#ŽŽëcÁ ³POP…ãä;âè¯H,áÖEkÝ Ã†.5숣͢|¹™Í^ß°ÊPÑK;‚uq±÷šáï¥ÕŒ/—™c»FzeÞ"è¥õõ« á_숣º°Fe¯¶†U¼´áÞœëiÇf››MT¯Ð+Œß†cG-3AeŽXG†}¹G±# ¿¢êxØè¥ÍM­ÜG,œ³Ýí~õ¥ÊµÖ¯çzX‰R´ˆPÉŽåع‚‘‚t¹¹ÓE„ ¦vK³9ª‹‚Ç3]—e^"óÖÀ - v?î<ï­ÄŒMkò²‰Á{9Õu)åwÈ1m«e6èïp6S”FÕp<±#޶,go]™ó’M¦=ް}ÁÈP„÷òqçY¹ uô a¥ŒÝî9)’ Å â{×lçs@x¼§n^ ª/p„6v1áØG'NÂKâÅ»Woáí8ë8C MºU0|òÀêèàÕs‡\_jcj§pì8l?ÎúiEMSЮå ;âhä.Ö…±éÀ˜o_ÞÔ‡¹cG½A8Ùu1ÈSÙ¨0;=s´ãìH@}A¤¥>„ª„ë¢SYx¤Vöµî r ÇŽ€ãöãAˆÿN•¿Ät<ò†q”{s zÕx/tÿº]Õ~ít[ìÔÑ[óñ í]³£Uä/~† p,Æ4±>ĆýÝËÇ‚¯1À¾Ë-Œ#Š"/,ܽr«LøÄWÒH¯Ç×ïf Žoœ?4ès]s¼o­¹ŽÂ±# ;Μï–ÓÄñ‰¶ ï7;âh ÊY`Ë^T˜xdÝ® 2 ÇŽ@{¸ò±è£[#tïžÕ™ù徎#×Ng&àøÔÆ=Áw8v^Л÷Ú°ïAõ•7숣·]2“¦֖߬˜K½~þÔw.w’ÃÇ>ÐÞ/Ÿ~×ïQ%ÜS, v_:õ¶qÄ„ö@P%Úã {%j˪ŸÜð o:fæR/ú=çaÒ—Úì1æ ;âè½ÿûW>â>¦½>ÂÃvÕ(ŽËñÊ™wû>¦•9~týýFUáØÝb<GȘqŽqôiƒ¼ÞÈñúøÍ_ Ú—¼aG°%tß3Ë•Â}ìüùG¿ žÉ?³yŸ4XX‰0gF¸p L°(ØG'Ó’;x=·åZ£?=öºàþÙSaÛš×?·u¿ñÛEÁŽPÒeÑügÌØc!áØGc_Ôý‰~ìd3ÎäŠýø°µBF…áØGå£ú–ÈÀŽÀ¢Aar\889vdkóú “7숣ß<¯Nö|Øø ÐAÀÄRÃŽL§fሺÙ,v¤Éÿ‚„yxrÌÀŽ$ã‰ÆŠ:ŽQªcáѾY/@ÃØ4¬¾ÌÜä ;B}œ˜ôÐ#^ëcåIK€,w숣7Vêº È^%HɳP”‘WjÐðÄbEñ$·S_‚‘ò‚G숉f¾¹cG(Úî5;C lム,8é˜cR0ÄaG‹rÅŽXÇ49¶Wå–KS=Öbì#±k±EÂŽpU” ’°,Dˆãᡨm1]•µa·ÅލV-,̧DU1k1…2ñŠQËÂÐWêx©„Ô &ôU;–ª@žŽ.T9Nìaûp숣‡Të•–œŸ(L¥bNUår¤Æ[ÕDj.5¯ç(æ¸Uá8Î"aGˆãLj–_O4,P‘U*±#D3*=Ô<5Lu° ÐÚ°ÛbGOÝÓàc —너n‹q"£p-jðéœâx28ªàˆQõ8*K 0‰~Ž‘AB¨ªYUoäS Êr¨ô9@cÕ¥†¡>ÂJé h¸0AÖ†Ý;âx jM¢µØ¢`G¸*NS†ªà â>25† ‚T(˜ZA<Ûà‡cGˆÆ¦'¦½>¢@‰ê£¥a‹‚!žãQE+²Ç¹숣ß›ž¤õH7UU–”eu bGíía(tƦ…xA¿¶¬:èÃA$Æ Z¢ –¿‘ÃÑZb`bDk€9ÂÖ”TZùÄŽ8úÄk£ªúX‡ä, B­I°‚è’ðÂÒ°*ÃÛbG½fQŒ8B$P¬±¢&Èñ¶ØÇŵô“¬¨›×ŠŒ»˜Â±#D=c òCªâ «Hç;âhAíšœ™š×Ãan®¬·*“|bG½ïÂÿI¯¢UåE%V0ÄÄŽ8Z/Aâ_¨h¨ñ’¢$¤"èu,A숣€k]p™  ài”ª…Öiè.Œ¼ò¬æñ׊dÙòª†` ;âh‘€R¥TÌàX™,k©n rì¼ÛµF†ƒ.ß Öv[숣cßøà(s,._c[÷.vÄÑ0 ¨_*Vš(qáŒ#LpÛûošVçÏ+FUAûˆ%ve@-4”‡ž„“½´h7GzÕ•Æ“Š£¶³åV-·(Ø"È38Òê€e©+¯¶N÷¢`Gˆ°®‡'Çè*:Àb úнû:ƵqÇ(U—V¶Öµu„°s¨{X_Ú¿Âd¯­[ÕÛbG\޽סð!™HV$K[ëW`åKFØGo^ÎkpÕ”š åf£ª`1è˜cü ï Þ ÖãöåmA ËkEP-TRWZ Æ;w€q´c©ïú8΃c1Ö,Œ{#æºg´D«/”Ê«=¸°zXÚ°VðРm s¬Û´pì”Rÿø0i9€Š³j¹|bGíìêº8¢‚——UoZÖjõ¾;â(ý'ØK{û[õ bVõ•4;7ø9^é½vâz ]^ƒoQm{ãÿ‘5D=˜R(uÖÔ®02ŽÍ'vÄÒ&jbz‹áq•ßß´Íÿö…u'숥—±ž¯ t‚dqYíæÅkVú€ïÖ,°#–¶T[{;¨tÙʪ%÷U»#vÄr.P;Œ1F Zö^àaȼaGˆà.1Ê‚bÐ'À¬¾vf?¹rXTÐ/­6ÓKXZ¢µn}`cnïÃÍwûÇ8WØK£ß èòô>l!?G¨30U[ÝáµaѪ@oN°#–ž®½­GÛûnЩ)8b7ßÝ;bi›ðTç¥k*ÛD¬¦¤biy½q=qüèÊ)¸¢Xö1½7-^ã7V­Y`G,5«í—zÚºUfè ô߯ø K¶Ÿ…õ¢Ô±>/…õâÇ Xó‹±èPèfÛðÄœèü¤òÑÖÔ¯ð»{ ;bé¸*døØ” 3ѽáþõ ^°WáUÅt.LeQ©ÿViOCàÄè Pä_7¦bÞ°#–ƒö›œ™²ÜY‘xI[Òœ`G,}I ˜µø& Äã‰SÓNøXE—cq¿mlë`®ŽD+†q# ìüœ`GˆÜ-5#òwL¦WÈŽ(ˆ°#sC¿3v$¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢7aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ>¿aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ>¿aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ>¿aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ>¿aG"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ"Š(¢ˆ>¿ôI°#¶ûO ÿ—­Žh6 ®fëzn¥¬­qSøŸx–¦¨šíö*+G]ÿ‹…U›±g¨rŒ(¨cºÝž_<ÏÖ÷?‹gëÿÌ̌۱X<Ü1|Öf¨WV,ÏÊqFwL7••ãÔôNÄÑÎôÌ4:vª)4ÔêèAÎ`ªR@Çðý´êØ &]ÊÎmMOÛ¶ªCk‰ÀÎë:j˜q+–L$9RçQ-¦–j*p*ÀqjýŸ¡&ƒ8b¦gTÇð˜P'…ZA“Ž˜UÍQ=d–1¢•)ðœ™AŒ1™HŽqlr‚?§“É,cœ™˜šä?óSyMMÍLSÇhJSAñ€&§§¦ôãNê:Ù8Ž ŽY8ŽOMÐ&%ãÉl'¦'§ôjÅ„¦“©@ŽÔyü‹ÉDÇÒ‰T଎ãŒÃì9‚F&Fd^à&Â< cô9Kä§ÒÙÆˆ•ƒŽ¡Wy©tàÊ ò碼‚À:`ÇÏ(Û¬ŽNŽcÒgÌfÌ_ÆTÇÔîFT ÜD#UKê¹ÊOŒfbj‚VF‡Õ8«à821Æ–ävÓÅ+­¦ó«ÝæÏEéüÀÎO)Ž™Y-Í/ÎÎqbrJ;¨ ÌñÖèP†c^AàsGñí²‚’À¦P[›>ç%ó²­œÑAþ\œWÈKÿBjá!bºwÇÐø!õ (P`'âaòñ!/‰¦‚Lj8<1 Žô¬±9ª:Sj¹bu¥ !ÖÖêøô$¶dž®(åPgtÒY9ªÙVfU=Ê鉼D(/h­b•¢c¨f©™OƒcàZ;^«¨¸rÜéRËÇÊÆ“j!¨€jÓ… ƒcªê`= Z GÔ›G›Ø‰ÅùEûß*Žã`ÙUœ_˜∭1ìŽ1H®UhŸ¡ña,0(ðÂÌN—â86þ\QX’J¬,¿‘Ìî¨-© lªä6‹èâta \Åo AfbŒ©¼Òü¢tGôüöèþÅJ.PÕŠLj¦F'°\ÇU‚âl"úÆíþ\YTÈËÿÑgT@µÀ¦nÒà*SĶáÀØ :†Ïé¼òü’Àývƒ®\M'ÓUY8ößš˜r¬,Â’ µª8ŽŽLŽa– SùXÁnÐ#6QUQ¹¿G?ƨ÷VNyAi RÀ6ìîWŸ´½¸¼6°óàȺ«‹+‚9ŽÜÆB²§ SXY8Nô õ» ­%åuÑdøbÁCàT–VëèâÏ5Å»ûùÏ%Á»‡úØ,ĒȦøÚûoðgì ly?¢B¶†:cî’(Ë/ÓÀjmýÎ'Ûª-­ _г·\Å{©®¤*°©®Á^cyAq6U{µÏåhÙË*ë`Ù÷ ç@ð.BÅñv/Dœíp,)â1Ò£š5‹ÖP'PÕ¢BϪ ƒþ \„––h>×—V6… B˜¬¨ZØ!ö#öZ‰æXÄÖK÷P?z½\œW„…¨†ÀÕLJ1F´VSRh'€#þ£Ïh*Û²oíéàÏ‹Êj&öšr8æÕWÚ X„¨Y’_XYXÈC»9Ô sH5URÈõÚÀMú ¹¸,X˜\»usÔÕ¡Ï`Xíbw^\^ȱoøVßÈ-‡c*oqa‚eΓ0ÁÖ( Ò¡ÐÑhÐÒfv}iU RÐuÜ1æg_Kl A#îLÂÁ^ì\2–P-P`b—õ2ÇTþÒŠú@ŽKP$UQ'°)t »Ú–8bwZ&·Æ†nÜêÁ¿$”P-ã¹®Ëü¹±bQ6Ž·»iŒ6‹²p„FèqÇX]T¸µa/uÞRMMÎL¡ó e5Ù8^Gµ±A½$ØUÑÁ±¡òüb° ÜÚàxýÖMÅqz×l!ˆô»ßB¨6”Õr¼Úw}Øu¬jŠ+9‚Ît^âÏ˪Š‚8BUÝt5̳åYDôpgŽÙÔÐé΋üyâUu % Žé‚lórï5æv1 —{®ñŸ²sìµ´P”W¸2ˆ#ÌT]­LË K°Å¾m¸Ó7•LV”Â4!%XkcŒ+«—vìĵ ü¹©zi y µØ1p£oä6ÁÇ~ÌÆú‘>C.Õ•hmŒ[MMNMbth*P¿@9¢~*™ªÔÕ9ª¦”̼:`¸µÁ±­a¯NB>7fçx±»]´QaUM£¿¨­¯M©njQ6ƒüXÇ9>Ôn®i äˆF®öwRSU…eè| yÜÒÝ6ä«õe5‹²ˆ¯£ígùóÖ¥ëëÀH€Ì¡ÏÐÍ5Ë«akC/@JCÎÃ^ t`E´Ü¼Ân[º>˜ã­îë·»IŒC ­® àˆçñ¹ ŽË«õ Ôú•^tl^IuQÙòÊÅÓ… ضÔùjÕZÐF›š¤:ðª‹Ë! ƒ9Ž _î»Ö;Ž©ê¢ 4•ÄBõÚ@·Ã±¸<›09tõ^[·"ÐóG©†î^¶1°©Ë½0!¥«Š+`–dss>×eáx[ql¥Ï¨°®ne`S°Ð”R¨)*‡$Éf¬¼r2ñ~e eÍ‚Öð/d8ÚYR^ètœ½Ñ ÍNŸaZ&è<,4­A|rDŽ~DZ*-(Z_ߨùK=íp¬¨cM5K5º):X 0z—–×:V`ípÌ/Þ°(€#úÜÞߥu_4Ë*Å1@¿Gh+åy«jÓ…F`a¢54¢[ _àa‚šøP«:_¨Ñ`)¾žÑ¡»Vnñ×±´ìmë¿AÇÍÙ8Þ¼Ú5Ô7>9¡ë, ô a“´t_ESZªÕ. £jj°þ#oce=þ ìØþËÇùÐ3ø€n»-¦—=öc`S8öá’Pi4è—Q¥Ñ`üCJ{Òì–fYœ.”K–kÈÝR†œ2ö§ 6!äóà˜c:f³í!L´7¤\¡’¼¢löRr÷Ô)Ü=ˆ¯`wojn‚¶÷bdE> t¬äÖÈäxa*Öl6wÏ9;Ò¡(¾@1ŽYÅ3‚›™ÐljَÚàþC/`™å'ÓyêÔ1øÈtH OÍLa¢ð_ §H48¦“YOÑ1XÌ0¡S:ªèÇÍØ6zާcÛ6ìöüT:061=37CÆY#>S“*°53Ï7™HB–vWéCLGs;O¡Éi{šÂ¯ÙÂŽS:|IÎl1S t:QÚx,ËV‡Å÷-Ûb@ATÀr€!u,ÄŽ!Õ>·ô;cGlñ¿¹bGœJNÍø³Œ!94¨ÂÎtZS@OÍiãàŽÑÚ<ã4eôMCfdI, ÒaÆe† ÀQ˜Ô o;Ó6æÎC„!þfÄmÍ4™HúŸ]ZY¤z5éåˆÉ‡l• þŸ˜ñÎj"nŠBô²RV"Qh̆Bè©àš:H–Žy9Ž \UM©Ø°‡#¦ ÊÀK‹Áàç({¦Z,^˜Î“+¼ ÁIž2¡h'§§ÀqÆË± '9êΫ¡ü!&ZÙ¿rfÒq§ÁòŸzƒãÈä˜ÁÓepÄ‚&Î̪&(Z¿11¥ã—üg6KBáºAô‡6Í pDÛ»!‹ÒùÆ1: Ž.aŠ‚Âí°ÌœaÚªçÙ  ÒµÔtž Áœ’æÀYí½É—KBÇV ýÏQFL³™z0òøÌNåÏjÿ°Š˜O ‡°ža¤²·¬ Äˆå 訤,I%¥r?b2Ñ”±rÀÑï¬Â2ãƒcœöÀΫ“ñqÛ+ öTùd«7k¤mHDÚ|.($ì]gŒŽ°±+‹Êü‚n6‘¶1iCSÙ<œ®Û½ãS™ØÞlâ^u%UþÐzŽ¢ }ó›˜: Em÷ò­Èyøfrkcà/‹‡BPÔý?D\mQ¥”«h^«°æ«ŠËå¬b%ßì×3š½º¨Ü¿ràÂqª ™×à;.ÁòÃ5ä(3¦qÌ1<>Ú5Ø«LU1FLl±ÏpWa•‘j BÉ£Åã»!"QEa‰qçÿ¦wV¡8—ÕJ±ƒoQGŠqK ÕÅåµrºÀ«óV÷˜—£?8vhŒ\‚F°òý‚[ƒ¥¾õV±`:nðÖ¦I«/©2ÎLû†oÝì‘%†KËëår…tíÖÍA÷²´ßŽ©ð»27;0ä Ní{¯q·²Ú_îéšÈüqh,‰«ý× ·dQi!ZÕÉø`¯!Æ—VÔxÇx¥ïš„¢zeaiCÐ_;ÏŸ›ª—:íXÒ7Üãx}¢½Ô¨ A; ]S\aÄ!"®öwc\V±È/v°ÀÀÔU…§½  7¯2¨eQiõ"Ÿ$‡œo¸aplªZêßÚêà˜O´Á±n¹Q³*A‡–Ö ¾h®:{¥m=€»—mì<Çõ[Žî<9¯–î«ã^ñI^ï ‡¨C¨­.Cëžåw`½\êé`ÙE„¥ÕT½Äoá¸r‚?¯Wg¯Ç^Cg:[ùÏ{Wl "vÐ%>{ÅÞÏ£ýðòq^Ñ5•q„<áýˆ.eÛh§®_¼år\ZQ—Mñík=J`zÜÕÐx:ÖÖ×ÙæªÚ²‚¢»V6uâú–™`·¬2˜ã—>v·­}ÿªíþ —zÚ¥-ai+zCý*? óøµ ZÛªæ -ýaNìKÝíS‚:ÞаJZ†øöbw›»¯ž¡ÂƆf¿±z¬ããG·,YˆV<ÚqŽ›zxõN£8¶Ü¼*ñ%ÄqÓâÕ’#vô‰ë-ÚÝˈ¹æšeÆâ„í/K Ñ”ÿ䮵§Ò‰¹²jI¶øå›ç8Ÿlk{ãz¿M‹õp^qÌô ·,^#… Üc×Î RbMír‰2é¹)•®f`mý ¿0Éqèêiú ž-sèê)|@Œg :¾zfÞ¹lc`Ы‚!&•…e;}ÂΑö³†Å"\Wï ù@Oa¡zƘHn^¼Ú¯û°*Z˜cQٽ˃…É+Ç{‡1b=ø•BG×é—À‘Ÿ8âùæ…›WxñT•ß·bs Çý—+OA7·kåfl‹BI:09v,ÛX-jâÛS¥ÑNL1ÿ~oî×'ÞáÏ»Wn…CaT€”8%b*–6™v.»Ë/ÁÎu]æ ”‹_¿@j¼r‚5M„¡¡ß/v·Ÿ¼~A–€#ž‘ÔÚã‡WNôÇÒ¬K×Ë1ÂÒ;pù¸1]س†ÉwæFëÙ­²¼v4®÷‹÷/¾é2]_·r}Px ôâÑ7øóƒÍ;rPUgn8Tx¨ùîÀ¦Þm9Ä I° È~úñküùëÛž ¬ƒUqº“9V>²:˜ãÛ>êv]¹ ‹V*>Øí¨Æ~sû‚9^o9¥u¨­­ÐGWßcT€à‚ö—`hKÛ´X²õHûã9>°j»kŸ¼Þ‚ÿè38>¶æÞÀŽýó¡åÏ­½×ßVòá¶3¢ÀÇ'ÖîòKé×.œ åj[XZøÏ¨Ù‹‡(߬ÀÿïhÜ`ˆ/¬ÀÃm§-Q êøáæ•‚ãÄôä¾ÖcjkgÞT ³ÝM[¥ç uüÎ…CŒ'ÂîöÒ¨ùÚÙýÔT]iõÖí6*ÀÒÆƒ¾áÕ¡hÀýú»¿æsá§ÖïñƒZ ¯)•!üû›¶ùõÂoOï½qÛ1·.Y› ò·þ’?ÿÑ}_ ¬óqûÙ£Ä]zfÃF¯Ÿû°ÏõD­ò™°ØÿõôûüçÜõB G¬U0¥g¡ôìF“#„ü{-‡éPˆuÇö¥ëaÈjÐû[Ë爧üĺ]ò hßåcº®È‚)¥|@à…%!¡ÇÆõX‡²+yë1Y‚F¾t×ÃR¿ÀAxçÂGŽêÒŠªÅ0ÀüáÉÿþÁOøós›öÛ–Æ¡J5ô?ßÿ £ÂøÔÄÛç2GÛåøèš{ü‡QÿïûÿŸ¿¼é‘@ˆ ìÞ_žx‹>ÃÿÊæGý{úÃ<†F»Õ6?ÇÿúÞøóó›õƒ_^9ùÑU…/ásÇêâŠÇ×Þë× ??ö3…WuÏ2:~ã܇ÒGÜ?¾ö>Ø`FÍ—Ot+té«[7*ÀQzùä{Ý^н…ep|íì>ƒã“ëvû9«Sú çëkÛž0*tõÁ 48Â2Ì!()L:b²ŽéçîzHäø‹ð´ÀhZúæó[•ààø¯§Þoñrl®i|fãþEø_Þþ‡˜û‚ù×¶>ˆ:ÂÒúÕ‰·-]¾xnÓ#FHBH9:¥×ÿ[]Óˆu(… é—IÈ%],SÉ$è_0œg‹ÕW>ì39 Óß¿xÞ¥ËQý¼ZÒG¸9SÓÓ\)ж‡Ön££c7ÌPš_´iñyZGÂÐø¨ˆPÿ»¸¢n•·ó•-7Û¦íi®“H$0ùJþ’†—Åœ*jÆ ÓX~IHgGÔ¯@`%l¡ë·»ùý^z¿º±r‘<œž™éRPõA1DÂ7ŽLÕI»Vn¸%CÂгCãÃÝC.;õO<¯-®˜3ö œ ÑÉqÛ€ožz½ª\:ñáÒÁ—;¯jIûÏ0¡Î0R ú#>¶mŽOLMÉðy:‘.Î+ðØóÅWo™ŽMª—*y,¥-LåËð±m)Ô‹<µÓ ,5/¨015Á[–í)ß»Çô"·ÛŒEý‘è X³"1„®üf¾a÷ú+P6+ó¬cÿÛûFøÒ B™Ø.2A–fËÔ`‰z|ÄOŸyìˆ ±ä!‘\ôÓ:±‡¿q™ÀÃև™¦ÄPe: ™DØF÷±#è’Ú9AO@ÂG4pdÆ?@K›üYã3O1f¬XäðGˆ * J ©2ŸØ‘¾á)ZöÞÞÓÛíFåyÃŽ`ñy·A•ìŽh²±/jÝ9DÖÍÁ^¿j°u Ј.@ì½µÀæÝø‚õBÃŽpÄòm ¨5u8vKâÚ-Ï{^?8b1v„86VÔ3Gø-„ÞQ¦ÏXZðͤ‘ÀÔPVk“pì¤D[—+¢=MÑ»¹.Ç1^3ÆŒaº ÉŽÇÖžkÊ]¾˜{{lHÇTíÒòÌÛ´˜ù¡±ËG)o¯KÝ3v€ª•ðÈçN÷¨Ñ 8´† ÇŽ@H̺F¼ÛêŽpíæÚeÌñJoæEUIEê% 3;oØÉóÞÓF&ùÞ§±Ìu›dmÝJ¶LÎݸlœSSuzuÒhN°#g:/-‡cY£J‡Ê0Ž]˜ü®ûœ`G ä¯ô]ø™m¡AC)„cG`¸Þh ùá#s‚X>Õy)ãâ²ã<ôŽØýþܰå£ÒüÂu¾à"ìÑ|bG°ý­í¥üdڼǎô œöF—™6/YÃÆá¹®Ë¼©=xˆdú^_(}N°#GÛÏx¦DØà;]H¼’®žš’^­K+*¯pÕ¶êot™i÷Ê-†}2'Ø‘K=nbO¯à˜`ºØN8pù’`çÜížVÃäP‹Á± —°ª a²±#ï¶ 2ÈÕñ÷&w@¼r"ð¤æžå›ŒW'ç;‚Å|Äõ|ï[±É€}Ì vv¸yeî­¹—ͪ}­ÇŒ!̹Çך¡ôpìÄ‘|³_Òãkï3\ÈpìÆ×(u¦ÛD>Å!ßA—ôäºÝÌñýKÀ"„4ms9ŽÊå' Û­>?p„&ÜSë÷¦c„!šìL¸—N¼;é;bBõ Í ”‚$< ClÎ v¥…@]¢ÿùò¦G Ó1;sñ—Çß6FGÿ#á#°Še*KìŽç7?Ê_;»ßk;ÿSWZõ¤ ûÇŸ{3pÔ~øÈ±#XÉCã>ÜÞGÖ˜H pìˆ8B”N¤¾¶õ ‰2oØ‘‰©ÉŸyu<È›€÷ ×pšì8þøð+ÚÉœ$IøTÆ»-‡ÛaËc¬^:õ^'¬zŸæƒOñí»ŸaŽÿ|ø_wZˆõMøNËGV}gÇ3쿼tâ뙌 Á1ynÓÃFáœ`G~uüíë┆Y7(؇ÿžìÈß|i0Èi(¯}ÞW9;ÂÀËkaÁïÞçŒÃ´pìHÇ@W¶­%aœò…cGàîaïŒû–„¥]°'ÖíbŽ?;úz G?@!;޳ÿ‘ †zílFkÛâÓ×·=ÁݯO¼í&Lò<µïï~9þÕ¾ŸrôÃGîˆù—#¯x\"8}ßÜþ}†_öWû~fù BK» ¿ôÎà>BhùÎÿxÏ×Ù7üÑáßfáXÿíO…s‚GÂ8JìHL‰Íš§7ì¡:0û_>ùžü–oDصb‹áìÜ;òÊ™½”¿PbG,íØnse>¬Y7«Š§þÅaŸzr‰!1÷á1íiÚšŒ+CŽܽqåMÄ$vmÕ—T¯qaàíj+¬ƒÿ“9].õ´÷hì…ÄŽàŸt*µÙ缇cGúGn«g-b6<+ÄI`{×ëîe:§ òÈ´µçš ;fºäô¯¢¨”±/o:[m¦ŽWcñp4 öI ‰±t¤€ÍÚé™i÷0ApÔ)Ù§é±#î¹ÆE1gÑ …cGpDåzMq+V$(ãfÒ]3³kY•XÎW$S× à7ãpõF¢§ôm™ŠNÇ‚à#áØ™ñÁ€ñý@8‚„0pÄß”¢aGîHŸy숀S™¡K[ˆÑt´‡¥!ÔC±LMìˆ%–µ\ë1/WºE6ŽQy„¼ -DË íHŸ]È™s ž@ƒ´é&£®—ö]A‚Á$HT¬1Ƥ{é‰Ê&¢¦"³eµüdÍ*D?Á˜·W˜.^à8êy1Î3F•VD#Q —=“‹‰WÍUœŒ8ŽLŒÏ8€JÿtÅ)šˆ‡"¯½àj¶Óù4ó‰âèÛvf2Ò'V˜W@àÄáñ*·ƒP‘>2.ÚMY`aäðÏ;2¥²‰dcs´¹”‘ªNRz, 9«Æ~Ä# Ó1¸7àèBOb^ŽI#Ž¡ÄÅ(9w³Õ)·-5·ÀÙ¹§—Ǩ«ñîX]»Ì€CåŽÑßfP;ÝG²¾¾‰6šÊzíŠh£óhÓH6;'Ø‘“-âb5ÁÑ@‡„cG®ßºyýV Åú…>ojh–úeN°#­:#tŽñ-‹×HŽáØ|+£qÐeÂ|²×ùÐ!v„hÞ°#Pˆ|œmùt(4Db8väà•|ªb4I¸yÉKÃ=ud6~~2%óHa)q¦Ü±##·õ·®Ã’Ê“!¥ÁÇB‰IlÙÿd,±K9ª’}—Žr¹ÑÔ¢²j#xîØèñ2mƒ# Hº–"Bª ÙyÚ@ï¬j;íXêîKµ‹¹„³±6v¤E|K–8’‡šwëtðÊɾázÖ”p…m!?:dN°#oŸÿˆû ¯éUUTf Cæ;òæ¹™ …Éaë6wëX|ùâ8&G¾]°uÉZC$†`GÐþ»-‡ØÑƒ¥$“`¡mÞ€n8väãö³m«^õÂí?>?¹nèµ³ûx\ÇÆÊEÛõ%hçpûÙ”4ïoÚF‡Úò¬aÉ.åjéü§Öï¡’WÎìÍÆq]ý ckGØ¢9ÁŽœÄ·ts×5Jm ܹŸò™c‰²±j¤?‹ó ^Øâ !‡cG x÷^:Ê–öÖï6´vvf³ BMAÅC4ɦæ ;¢¾m?˳ ã_ì|cûd^±9ÁŽiÓß*R5ŠGLË [+ѯÉýèðoe¹œ.´ùÅZÚxùÔ{üöº*Ï!R(úÎ…CÄU;ðÈO±õçïìx†Lô¾ÎPFSkj—“}â¥ïZî~0ªaI—×äŽNyûüAÙyyëG‡äŽMø–—#»u¶ƒñ´‚+ôã#¿åŸcËKF‡x¬pìÈ‹â[JlÀSQ]\ñ/ž ;‚o¥ÛUš_$±þtß—É ûçC¿a}çõã4:d«ŽÁ·ø/c^2ýû;Ÿ%޳ÿç²|L¼á¶¤¢îZµµ÷ßú?¼-ò|`’y õ±@¾¢5>Ãçì~Ažd†cGðí¿y5 G²n£F:¾rúÖw~޲çkTò{æ”ÛfShçé ÷[ÚFýÅñ·;úÖŽ§½†\îØ«Å\LdgAÁÓyþêÙ}tG[L_ïk‘¥­+§ ¿ìÅr…cG®ö]?Üv†A)eEO3fâ‹Üäý­Ç{G¨Ê‹YÓúrzkš '8°Í8 €Ž/¨ûì…]ÿJL…±Æ¦&²sÙ]”tËF‡¢T}2Ãuø2&<8˜.ŠE¹àÈ <ãÌ-;â¼¥¿¦³#†N`Vé53Ø!Wû:3©8’)²…ˆi}Y5ctõõ 2œ%ᇪ?âñ8¼{:膭³ªP*ޏ~ÅÝáX”Χ4Òðëoõ2"„LŽvÁc¥#Jx—®—A­ÅÜÛLTäMÉ %áØH˜Ag;¨*ñLüE5á¿:<;¢ó—ŒPObι½ó•FÛ$)¬ îC;‹¢“ úÈOæÑ阺ZÁ‹«È râ”·žã¢±LEo$zZ4àAjÝ•‘;bg²9Í8sC 6σŸ8´-ã­(#CI(vÄjáóFŸmìˆH:¢þÂòÕ%"¯»¾¹FÝóÄ}OͤRx—©ˆÑ6ÈDL)õˆ¼­&¦…¸q‘z$;‚LÎLñÐÍ2r#¡2˜ºIGT=ÒyL„L™t„¶ñ„¸¿=O{·ev}àÇu§ ·„FM©GÜ¡ú‡n횘šñC#éHA*Ô·ÉdX«®êÛ¿8©§o2Ëà? 021ÆcÄ<€ãØD˜B©G žµAæTƒ§Š£˜t~J Rù”†Ä…Ë@Rx’Ž`Ô (A˜# hN:Bs-Ë@h °Àù©aº0¢Qq›Œ?õHîØ™t]E7ÐvÒ0Ï0p1–Û£CÒ·DO¤É¸¹&wì’ô%V5Ý_ãN—º¹F&Ñ€’ô|ÈËZ.ÚyÃŽô ÷óU;E©0‚‚çyÆ\“ùÁŽ`õˆÌÞµ%UãSãrž)õºÊî U•¹iH´<ÅêKª¤#°& Òù}ÓîîÀåœ,4ìˆL:‚µWUTÞ7|{xÂY9ØGFLtAaG8鈥Å8&K±GL¯M[¡Ø#éÈb}®Ñy»‡Å¥é¾ÅÞVªáir¼0nÅ+Uê™t룓÷×@¶Ô•VQÒËGô\®ßÊSà_ÉüáØ™+ kƒ§—R@>Ë„Ë*°e‰‘z$;b$Áä`Œíý]Ì‘n!u“Ž8£\UÓˆÍËyÐòÊ,!•tÂJ—b¿,­¨GÞ”z¼ZnRŒGm¶E¥5¨ÙÖßÉJRȤ#(‘c\^µX^J‚1’Žà¥©+}×yÔtsN:ÒË긹fv®˜×#¢Ô#­=í£nTk¾·¼¿ÆŸzd~°#ÐÅ2!üj(ßÖÞ6Ò(õV¯~/A<¨¦ê¥ý#·ÐÀ©GdÒpÁ㸤Fí(wx³ÆsÇŽœ¼~»Š)Å:Ä#cŽ…ep!"ZERå õMð“ωT+†÷ž;vÄH:²eñH*§D·»®~¥Ô¹!ØGÅ šX %§o\bab¤É;‚-|\¼öÚ¬r®¦Ïv]æ,ƒúæšL$ ;ròz ›ÕêBî%˜7WŽÙSFê‘;B4oØ™t*xóâÕ²ÚÓx'/;‚]skÏÍÝM[!ZeN£í뱡0K¬£! ·,Y£Ó8  ê‘ܱ#X„$äm½754K˜,Š]+6CîÇÙx.0‡>n?ãèqA KHÞVƒÉÁ»ûd#õHîØ÷¶êjú¾å›nõKí°§iºŠGÌŽV6Úá¶3dCÚÚ¹»q„Ǽ¿l{Dz ©xòP&ÕŠ™zd¡aGÞ8w€%pÁÚ;xõ$ëPc›¯ÖIGN2ÀôáÕwONOCª0žÓ+5`îØ‘Žþ.©ÈžX· K–©GrÇŽIG¾°~Êã-ÐQ6ï€ûèê)ÞVؘsì6àý©GB°#ò¶3¯½ÛG¦!1R„`GŒ¤#Ð…é¬^6ä(õˆ¼­-?²ú¨È#&B©G^;»oØÕ/«ª—B±¾é‹DØ„¬Úy%ã€éDòý‹G&Ý;wèÔ#2é$ძ¶CEŠËJì/Ýõ°t#ìQîØ#éÈ=Ë7-©¨Å#ÓùVÕŠ^S·|ÛÒõFÒ‘¯n}[O–©GrÇŽ` Ñ ÀÖËþ+›óáå ë™ HŽ!Ø#éÈCÍ;Šò ±&B©Gäm5EyÏn|vŸ@€Qꑟ“/¾YW·ró’Õ¯ÙÇî!¥LþÍÉ÷ضyrÝ.x¬¯ÙÏ&:äùzqWN8väÅcopbHü ŠòœÅ¾?õHv›] ùç6=,Kü©Gæ ;ò_æ##X•«k–ýæôû|‘z$wìˆH:²!–W.~ùÔ»¬h e Œ¤#xÏsWú®ÉJ=‚g§] ešÁÏÂ0J=]ù£Ã¿åbIÀøéä»|I:¥9q½EƒU™”<{¥÷šLCòÕ­O@´RÒK×Ã}dõNȶ÷Ð¥¯{¹cGþñ£ß¸ÑDµ¿°€uüm6&ý©GrǎȤ#›¯Ù¹|ã/¿EÀz[£ÇžÑÑ}¦ìÈ›çœírô ¬Ðom ö kê‘숑t„2O >ã9 ŽåÖÇŽà¹ð\µcý¢•ÐY|fH©G ž ¬X˜à¹\ìi—zÜÀ(„`GŒ¤#XáPdÐYŽ‹š |Œ¤#úÀ7a¼J%º¿¿óYHu™tfÃs›yõÌ^Vm”z¼þë{?榾¼éa”ÿäã׸Fê‘pìˆL:+Kî•Ó{O99\Úâ?Þó5N:Bm`QÁûñ‘W˜#Ý\ãÜVC]Í+þÞ}ÏÁ…¸sgQê‘ÿþÁOٓůö4mÅ.æ#ÖÆÊEßr“åŽ!°Åæ`m[º²®O…ùÕ/àf>ºæÆ—N½Ë€‰gïzÞ€F›!C –­ôw±#/|g’®¡ÑÇ#˜Ø½—>†7MíCVc `§Øzœ£ð¬RYå\9 Ûž ÏË['¹ÉtîÒu÷òT<ñ ¶¯`N¹æÚF°8Öq^Eˆt[0 Ó`Ã,d| ö žìyX¶.šƒRÀíe „>ÓXÙÚÛÑ«¤„*ƒŸh !C°#˜äZ]úëõõMxôJ¸Pxvp0±ÕRT’W´¤¢®óv7úæ j’I8›3ö m ÂŽ,*­I%°Ûùº˜.пø†sàñ¥uêw±P[PÊúâ› j¬0• †0ˆùxbQiõôÌ4|ÎŸå½ Çoóã'™áØ|å:ÅòRéâtüYJCBÑd#õHvÄI:¢Ç“PW%dÂŽÄ»HÇòdÒõ~2¥®npK~2­“ŽŒ3‚Fâþšœ Ôœ”QàX,­Â»ÓîzS$"ÑÎ<'â*äícg ‚[¡Ø˜~F”Xî!Îy©žtJ4â¹M^—Ø^LNBP väŽôÙÆŽ8€#‡‹Ó‚D*ÅuN‘iqý e12‘`OÎx@'6倚Ñ×Ó¸À°ÓD.'ˈð— ÁŽL+ÐÉ4O¹‚òÍãdBíX¾”‡±] ‘R “˜n§t–´3!:–`GÆÕM4¶å¾øNûY‚!4(8æöÁÖ%i´€ÁÊ” ÒùøSÂ#èRf"Q×n%Rh\s´©ó©D ¢Y¾"“ŸÔ?œÊô¡0¥²Œ@Nqûø³0’ ñR8þŒNŽq<ì0^(DgA—46Å¡¢t>º4"Þj*N‚…ÊD2•_ÀÆLfÆèfAû¼Àòôí6;LYFŒL$·!À9cGÄ=*’§p¯ÞL$0þÐó‘‰Ì[ tj€yà¾Æä9bG0]üdÕí3NVƒ^ÀPT% µ=ijŠeCêYbPGÞÄ4?ØL`¿>\ ƒ™‚ùAežÕ˜¢zŽÒæ;‚ 組²SÀ/å¨ìj]ƒ½3Pˆ2zÜL$NauQ–½œçºÒj'Ò™HlwNäv^(&ìð¸ù¡ü ¹Ñv¤ëvƒ{ŠÜ,#2j E®í숼‰†³ŒÈL$XxŽ×nÝdŸòŸ·öº/“ÙÊΆ撳JYFd&Ìçòªp$c—…ýàódbí%2oJv?‘+MaÕéL$Î!ùòÊlg#]eŽØ¡2£{vdTe ÉŒ‘²ŒÈL$hÝ€#áJr»ÀÍ2rµï:?µª¢rŒñ¼ˆvS–•‰D¬4Lä•;Fµ'›k—až1">9ƒÆJÃpX¼p–™‰¤¶¤JÞ‚¹5:(ó=PNiŒˆgõ1«XoZªÞ«,#úD̉dFT‡“GcE=²‘‰ÄˆÌv"Ž·*g‘™H ÷0'º¯òF€,"©%k¯¬^s«Å ‰YúA—aŶ‰ç¸Ùû"fŽØä (Aý½t&L J ØIÀÒ¤<±ö>èA~ñ=‹S´ÓË*Úa‹8å\PØÈ Þ8–7@7AùòSKÆ“¯½·å&µ ŒTØÓDçË'8e*Ã*¹cGÎt^ºì L˜O„|úðòq”õsÇŽò‚Bè¹P&zÖkj—C)¼tò]þ e12‘ÈÛm¬PìĸäHBþ·§?`³ "QÞp‚iëïü¸Í ßÂäxFSˆL$à{Ó¶ÄM4œeä—âí[”@þæT&:NYF ë?à½`ÛÏoy ëmpü¢rp&[{ax ï_<ÂvÖ0Ù*"Dg£ŽŒwFآܱ#hA‚{^Øúüz7‰¶« KŸZ¿çÀåìj1ä•3{Y ß%n·±æ;ÁN®œ­nجÃãÃçŸ|ü*/{HZ¹¶C°#½û[3ØÄßßù¬åd"qŸàûĺ]¯óM4Z–RDó>z™¸{åldùâûkwÕ—Va{ÊPîwïù#íÌç·v¨ø"ž;Vhç¡(C°#Ðà/{ƒ³)Ë6¬|îxïsrVC°#3¬/`´“0ùá_q£þü`G Ð,W]R–Ôçt°IäÚÎ;‚~sŠ[°ÿàžçà¿@Ý3BÚä…-c׳¾à,#??öëºÝæ/÷½Híàÿ(ˈÊD"TÀ·w< …òšX$ß»÷Ëàx¸í4˜Ò¨! ¿t×C¯žÝ§=SUuI+áoü’>°,áXýÅ?uºîf¹®Žx y”#vd|jòìÿÛxOmس¢j ‡À‰þôoÊÖrÄŽÀäø‡ƒ/ñŸ_ÑYF`ÑÉuòŸü–l-;òã#¯°FÛ¼xÍÚÿÞõ·<*OçB°#°gرâ,#2 ¬8‰s ÁŽ@¾I EYFd&QxŽïµ‚ÁLC††ú½»•øúÙÑ×ù¤ †“´dB°#?2íY^2-3‘ ýßßùE,Â3®†B ¤È •ŽÖý¸oÅ&¬ÃÿòÖßsS”eÄÈDòýÝ/@¿üJ,*<2p„ìe°øR•Å$³µÃ±#ÿכǟ¿¼ù‘æšF‘‰Dýàyè;°*¡˜,·èÿxì{øðÖ…ƒG\(*dï·¶?…%ÁÒxã¢U”eäÏßø!7õÔ†ûa:þßïüsÄ¢j®]#êLJ_¡’X,Fí3åˆT r^±Ü%DÄÎÕ¾ëož?È( ˆ8Ç®§:œÅê³v Q&’œ¹$B°# Ý{€3…<ºæž²‚è—;ÎRû0Û09维嬋°Ji‘mOƒ…7 ÿZ[¿TkСM5K§¦§Þi9Ä—ïlÓÆ$9€4"¬¥üT„†IG¶b³C"QŒ‘œ#˜%·ÇP ,j;­¨øàÐ,#cúÄÀÁ˜@ÍIK;;‚õàØ3±Xqº€Æ‹ÝíÎCcØ0f´¹èL„6¦ ±*8Ù œÍñ© :&"ìHSõ’x,N ªi" RyÂ]·{‡'FinÐI²:ú»¦l'FEa„€²ÏùSЉ"2²€¦Æ&ÇÄÅŽÐ×í±¡aJÜ"rº…`GlÛ†·Âh„Ò‚"üfJé8 2;2<>êxè12£å4¢¦PÇÕ<¸?¡×æñ«ñItbéÈ ú$[g"Q³Š§Æ(òüb¬"'x£Á#q$_XG!„Œ»q”P£[‰±t!ܧLž‰ÄÒá !QvD~ÉF!1v‹B8~p/9wv%xÔ€’Q ó ®ö^g@7ÔØãÚšùÁŽtª„"ιžª”Pá‰ë˜H]±sCÄŽ M¨ÝV‘‘›ÎÍ!«ešî¹ÅŽÜ”û‘{ (±õY³„‰ð 5žÂtasm&Þ™;väÂÍ+¬÷!%(¨æº‘õ&1ìˆqa ÝGXH”;v_q&XzÛõI½(´uáz®‚1.¬Ñ7ÔØãÚš;B4oØ‘÷/áÏ  ,$ ÁŽ`;+u©AÌnгt¼ã<ëP*”Ø‘-KÖPãï¶…€HŽØlÒCWO9ƒ×:ÚÈ2‚Â!L`ÛÓ¹äåÞ°ª°y‡Äެ¨ZL3°(wìÈ»MºÎÑÊêÅ$Ld–´YYXÆo«[ú›]¢B𰤥qEA a.u·sü²Â YPØ•PD@šèžO¡­âIúš[d$0DbG €HîØ‘&ˆ©/­’":wìÈþÖcìD¬Ö0.¤g%Å–YT:Ú‡ÝGײ…ügvdߥ£l'€é‹ÀB¢ìˆúê†óX¸çìL}ÈÃGVï|íì>¶ÙðsBî¾}á ‹;²ÂFÇŽ<ºæèJVC°ýhkŸu³ŒØÚBC¡|“ì`$±#º0׈°#D¹cGŒ kå ±#ºðé·Îèr;Ã0,r6V±¥e’;väsh¼—ú¼©¡™lÚ7Î}È^ó¦@$;½É³†‰Ü§ Ïs!dï³ü…H(‚Ÿo^¬ð—/Ÿzõ L躒ê×ÏeØ‘gïz°½ïÚ§éƒÅN€cçÙêæB¢ì¾Roü»;`"ªPˆôoïxZ& ÁŽH˜ßP# w.»K®íùÁŽ@ÙC£ü»ž·4 k€ëP!QîØqabûýÝ_¥B™]é»¿Š§ÏÞÁD,½$¸Ê…?rbÉÊ4ûâ]5”ÕLLMÊYE!lþ#™DJÖïùþ•ØПìùÚK'ßÕþ…*ƒæ"åõÒÉwØé@ ÚÉ…‰Ø ޵v„ ùϱ#ðAôW¶Û‚‚Ø ’#vD}%ЊÿIÃD¸úñ÷|I¾þ‚‘_a…“£$±#Ƶ5!Ø Á ¾ªÃö…D!ØP$Dþ_þ=KÝ^>ùž,|QÃDhÈ|CÄŽ×Ö„`G°æ¥µÿ¿=ò]Ëw‹ ¡Å¸qØHd&ý„ u?6,Z æ¯÷ýœeG^ž” °½ÿ†´öÿìÑ?°´½$ í?{ô¹Bvĸ°Ê¡€þÞÁÙºð©¶þNéÖ”Tþá=J`Âïã Rð"±Ñþîà¯Yyí^±ewÓV|øña”¨¦v­ÜÚXYÏ0K+G8zvä[ÛŸ’îmŽØ‘ë Óöžå†,±Â!Ø´îÌ^ÆŽ Ù30ZºZݼ *Ó•%4 ÊkKªdf»ìl6yËÌó[³ôáÞÞÖ£Á„Äøèê)uEŽ.b˲ ê˜[¥]h%BBÄ´~¡8´6cG`Å%I² hDÔø€pW9§lBò¯©NyA1ÝF$±#tm ZP rXÚ-bìÈšÚåò¥âì¶žcÄb5Eåt¬t¹çÚðä(± ¤Åço^æé‚×_¨aB3vdiyýèäù 4tð%±#–ö×èætš>ӾᾖÓGë…éü·z;R§Oþ'§'»D¼†«¾ef˜º•J¤ÈÖUoÒªDæÎ숈D;ÓJæÓŒms40ìˆsCͬ°#–+¢3)xpv$wúœbG,ﺜ vÄò]Gúoˆ™÷ÑÌ;’ÖÉHøÏYbG([‘5§Øo2’YaGŒ }­ vdFÄÀŽ@ºQ¶•9ÄŽL«d!™d$³ÁŽ qH^™bäß ;by“‘Ì;by"ó€‰ëd$ŽÀ0™ŒdÁbG`J 0ÿج@já`GJóбaåÊ!SoBD>vĸа#V(@dAaG®Š#Œ¹!’‘Ì;"SŒÌ;RUTF¡ÍO€ÁSè Ž;âˆÌ;Bþÿ9ì„ä¢RÅñ“aGdŠËÅŽ@È„+v;â;[…íλÝÖì°#±Xœ8~ì'#!š%v„¿’ØK‡·Ïˆ@øg;"SŒÌv¤©z‰”Ã9bGdŠk¡bG°ËhkKìˆ ²@±#:ÅÈ o¡jwç2@$ÂŽý»ÄŽ Íe€È¬°#”bÄòbGÐø²ª†c™]?Ø‘‘b„±#–‹r;Ût€JbG@¬¹G¾??Ø‘7ÏàõÉØ‘Ãm§™£;òøZ˜4°#—zÚùWŸ9ìH‹øÊú±#PUl™|ªØ‘f7Åȇ^@‰ˆÌv•Q(SŒ0LD&#™=vD¦ù´±#–zÃû´cìˆLFâÇŽ<¯Ã~vâˆÕëïŠyóüA÷ZÌ;2¯ØlØ.~ü;aG €HîØÌ$_lôicG,•Œä‹ÿ(RŒ0vä5‘ŒÄÁ„§);òĺ]$Øç ;BÉHøÏYbG° µÑâ”,^»ui&ýÕü`GÔWÉ!±# ò×™ìn‰fƒA³(ÙùU;‚?þrïϸ);A‚9ÄŽX òSæø©bG°YJôͼÿ¶Ø É4;K왂sˆ‘ÉHf‘)F,;b$#1°#P‚O®Ûe}Rìˆ&bù’‘Ì;²¤¢v׊-†²»#vîÛv«­:‡Ø+“Œ$;²D§±¼ØK'#ùó7ÈÎ;ò'ú›ùÄŽ|_O—H‡*¹1Ø3oØ85ðã”mïÅŽŸ ;²cÙø–;²¢Jm=JP={ìHUqå[ýØ<iWÌ;RçÖIìHQº ¦¤B}ÿØ‘x<ѤÎ'ÀŽ {EéB¢õbG,oÚr;’N¦É¹Ø½T2–Àì±#å…%I}Ì'ÃŽdâƒ;BaÇlØz(v$?™§£É3¿v$‘¤Î|ì~(!³ÄŽpà^bGb2kìHÌÅ$|2ìˆmÉo>¿aGœÂÏvD…ç ;’¢áÌ!vD§Hš–…Ÿv„~Xvä3…IÆãe%Ÿ]ì )ñæ;‚ 'ÔÂ'ÀŽ”ç—+'ÂŽXŸì¦‹Õ'ÀŽ4VÔßê°#óÁJ£EØ‘ùÄŽ¬ÖÙðŸ9bGº‡úä Ÿ vO¥>8ˆ°#v„(ÂŽðç@ì]dÃæˆiªYzX¼ùú™ÃŽÈëi>sØ,ª›CŽ`ÿÌaGäõ4ÖBÍ;òï;òƹÙ‚úÌaGÚú®_Í\ˆó»aG^9³—Ï["ìÈ|bGZ{®éxç¿%väWÇᑚ ;òÝ_´´l`Gàga…/pìaG;—P>ÜO;²H_OcÍ)vd|jR>…O;òv=Ÿ—LF±#üÕbGÞ»x„o~üT±#؃¤¡>‹Ø(»?¸G Ì;òÙÂŽ<½áþàhüÛaGêJ+aù[Ÿ;²¼j±´´ç;’L¦VhWý`GJò‹ SùvÄú¤Ø‘”›Sà“`G İ#ŸQú`Gb1Yí“ßYS€©@˜ÈgãΚdZ>†\î¬I)Jl6Ø‘‰©IÞÿ³¾³&M³$±#:}HŒ.H#úÄwÖ`Dù©¼Ù`Gðà$GÂŽ`€™'bbG’êâ±<Ë‹I'R£&‚53t‘ QŽØÌ0]~FDŠÇ”x±#|=ÄŽ`fdÃy»³Z“ ÃD%Ît-ìȼ³†’‘ÌæÎ¬[ 0¢¢²–ÄîX°Ø¬pùâ>aGÆ=ȹ6ÐÅ“±#W döØ?LÄ ºÈæŽwÖÀ¥¡\-Û5݃}ƒ®8bìÈõ[7%’c–ØüÄ Qá%}‘M·(¼ó5œ W‚Á´pDßÊáÎL ÄÂyí&ì¤YËÍÌKÆ(Ë2øÎš¸”Ìç5гxŽ&2f`GZ{Ú•ëåbG øZ{:±#MÕKäÚžìˆ&b]dsúÆE6 ±#X½èü<ßY#a"–‹‘ÙP¨ۓ̓À¼#eùÅ2¦;wÖà)ȳžì¹~ìLJúM4·Ø¨Š^Hìˆ.Ìp ÁŽ`_pðÆÊ‚¹«¡¹P¬í;B´p°#sxg äVÚ<ßY áw8vwÖ@¾íZ¹eþï¬9xùÄmW˜ärgÍýMÛ°åÿÝßYóqÛYgÍŠú£ðÑÜbGêÜëi$vÂëœëÏ-vOâU–;²¦v9Êý×Ó@ û/²á?çÿΈ>Úª;¾X«Æõ4„1.²1°#®Þ /ÀÀŽ|aýnx³¹³æ¥“ïò¹Ptg Ñü`GÎw]AôYÝYÃ×ÓHìJˆì5úzš,/vDJvýF\OÃØ‘Ÿ‹‹lfygÍó[ƒ`ÿ”ëi ìJ˜r¹³fOÓ¶f¡Dæ;rµïú›úz‰¹à^dc‰B¢Ü±#XÞ"ˆ>«;k664ïÒú”`Ùÿð௩+‡;kà}|çîgfƒOúâÇN°ß^0wÖ|cÛ“Ò»Ÿ[ìÈ÷w¿@h‰ù.ä:¹ÜYóøÚ{IÍ…`GðôÙ×ÎñÎ?LÄúDwÖÀð#(QvzzœÿœÍ5Û–®#(±#Û–®…ñ`ÀDè¤è¿½÷cYxÇ;kàÒþç¿ÍB°#°Iþjß‹ü'aG $;R¢¯§±¼Ø‘Z}‘ͼÂÞ=cG 9µF ÆŽÞYƒ¦äiùÜbG¾¹ã)ˆ;òÏÀb9ví¼0!CîÓ¸³.^G—!Û>v ɉٴx \ž#º*¯¿)Hç¡D#f<Ø‘‘‰1æ˜N¤0Þá‰Q^9è<˜¢ªñ:)JØ(}(NÆb&ƒÁã€äŸœà}<ž(Ò¨èQ~î˜yp„¬gH†ƒ1N©&|LI^‘Ü)9bG,oŠ c4°#¨Ù˜Ò²˜#~%í€Ü±#˜@>5°ôᦥuž@9¤ÀQ¦Á²¡@£Ä(”æKM3?Øì){Žå„Ê<«XròHÔš/ìZà>0v¤gx`ÊCTÆÝC}SnÄ€ƤéÓRg ÀÆå<וVcçJìHZ!?2c\PØK‡!yëáY`ùØ#ä¶ °#x@¼ö`šÀ\bGê½õC°#ØA|ÖéA£–ÉH°ƒ`µË²³! 3mu<”Š'ÚÄ,¡³ ÅÏí7V.â[/’¥ú¹Hì§…`G°¨äs/¨gDxL‘,aìºÊOìªDD';‚Ÿˆç¢Ð*P(2 ê/­¨Ãêw€b¶.Q³z¹·ƒašØAfKw›Ò8šü",FÔ)J;r®ë2o´ú’êEe™£íܱ#78È¡° µËñádg‹²Ü%!µ[v‹ÄAViòcG°×xëçˆÁ†jˆœ:`ÜÖ×yÉ—ØØ°ôþ QvÄY”­,Ø‘{¼ÁÚ;B4oØ‘#ígØÂ¤ëi°ªe$oç²»è|„(;rE½ßAnÖñò#mgx›4Õ,Ń8pù'[¥K QùIKC¤ÖÎ;¢†ñ9¶Ž/ÖWô‹d$–>%ÄÆ‘%èZº¯:JÇVQçM‹WC°wÞr„I.Áy‘ ­¹cGŽwœçuCY5Þ8—¹¢~óâ5&²R-À#Kž)F¡qÊ]ÆÉXü‘5*|{èê)Ö¡P^rm/(줽Dí^¹ÂD^d£è¡Õw·Ü¤e$ ¥µØÈÿf!ÒsÇŽ@´d° e÷êí÷/á· UVT-õsÅŽ@qèå»Vn±t~Lm€‹Vv„½Â­KÖBBÝËd$O­ß#}ºìÛc°ÐHÈËú[—®k6; íàåŒRøòf´8Ò~¶Íµ'¡‹ñðÈX'ÂZ& €Œä¡6JXzßß´ [‹œ•Lñ/Þõ„GL1Þ/ê~¶–{Ø2(aG k˜p®;òÀ*ò#ÂŽåŽA R„¾°õ1ØŠ;¢ê¯¹÷ãö3ç\{± X„lšn[ºN®´Ü±#° h£¡pÐðøðùŸý†+`ó˜(;‚í#Å×ïï|ÖÒñKÆía{â¹ãóFCË´µÿA$#y¸ùnÔ”%„Á¯ÞOá»÷|éRw;, ç"‘"DΫg÷u¹æ4Úߣ£•D!Ø‘‰éÉþ-gSŠˆÙ½—Kíûî§å¬†`G —Ø 'ì ã>œy FýùÁŽ@¼ÿJ`¾±ý 0ÅQŸm!h‡ç° wìH§ŠÑr öÜó|(‰Aý/n|Šà”»Œ©ð8جÂ"TØ‘¿Ö§‚Ê4ÃB‚SIø²È2õ½{¿ ù/K;‚EˆmB£nÐÉHÞ¹pH;ª ¾'­„¿=ðK>ç|¸y'Úÿ ÷z[/ †ô`Gþ§û¿.§"Gìèÿ{ÿ'v¤µ·ã•ÓˆäŸ>ðMY?GìÈøÔÄ_ïû9ÿùbÎ +:·ùcøa ÁŽüâø›|^GØ´ÿ—{3@„ç·<*OçB°#òzØ¥ßÙ¡¶Þ‹ÞúÒ’ ÁŽ@åIøG÷}ŽLF}ô»Ÿ9pù8J ì$!kL°“–LvÄH1‚G–—LKìêCmAòÖ£|øëý?Wf•îÇC«wÀ*øoïý˜Ï¯°¡¤Ð¾Ô€ÿéÁoA¿üD”v:‹Û‡³ömµ‚±2)FÁz=i`Gþ÷Ǿ“òW®­bë#–¾øÍoü Ë Ö Ÿ°ÙžÞp?>üù?ä¦PÆêÿùÆß2GÂŽÀàü…Û~,£ö™rÄŽ`›ÿ¢Qô" bß¿ô1Aò’),‰3—>j;EuŠó ^ÐX¥7Î~Ø5ÔK¿….–(íì4ø« èìDtàŽaUCìl¡ö Óù¯½ï|—¶œuV)€%v³ Ëm_ë±!u"§ZƒŽƒ×9:9¾w±#;õÖÐØ;rß år^éÕ¬n«(¯«ëªrÃ; ì<²áÉQê,ÀsW°*©Å™Ó'vþ{žY…`G®Ýêî¥=‹»osaàDcP[ð2`]ÏØîB»¬ ¹«4c“t€)±#0z sÞN¤—inøµÉ¶¾3Ö ý¶ª¨Ï·£ÿÆŒ ¨)./Håû# c“ãP£n\.FÑ 8ïúBUL/åfVZv숥E“AýÁ±a^'† ‚Áä8®PÌÊSo§«ãrШ),°x<>4>Ê1EzI¿r´ž~’„™Tz–&5FÁVL…{£(ðøÔ¤íž9vÄÖÕd248ÁMi`B«Ø3”«¼#³ÅŽL‹4hÇßÅãN¶w8.vDw#ìȧKŸmì¹hì¸N"Y;éCì™™ƒNb‰˜“>„›r.»™™áþ%°NUê›~]• ½}ð#§²bG,-hxW%‘VÎÆ›q!&º6íŒâ˜é;uޡ̈(’DÌ ÁŽ€Ý”{%jL(%GÆ †2î@LlÝùªMLM0Çd\B09Æe71oŠ”ü”¸gQ¥“é '’ñ “c2¿ ¼»ñÉ ~Ž`‡hÈ8/*ÔAÉ‘Àwb⸠1¥`Ò4~ÖÄqx"‰[q´/9æiPˆ¼ÅÆÖ(9Bèƒ#” ‚cŒ3\)¡@'žXZîØô*3F­ èyõbº4>ƾ=6ÄcÄpRñ¤Ìø‚:ia"äŽG¨^;Ã1J$†š¤$¿P=Ù© sA70X6©c ÁêѲ󃱔Ýp›wV2–(Î/Ä“âá ŸxX²þü`G°¥Ñƒ¯ðL%2 þÖñãSsXPz{|˜·^JAh+¨Ï¬¡ ©S\Þy«‡9bf`gcéÊ[~ð¬QAbæ–W6È=‚±äÚd†cºJÝñ”#þ¬Òﹺð Õ Ü”@„²â[Yµñ\TÌÕÕìpe±~xm@:QÜ·µ§ƒvŸ­t” !J<µš‘ÉQÖ´—c ÁŽ@ø_$P‹&¬Ï¢tþ5‘<›«È/iéÂZl(gVmÅÎ?Täõ›ý™Ä6˜®rŒ‘'í[óƒÁ~‘ð ÈR0’ˆ< ˆh,<ç^!maŒXr†^«A!™w&4nóƒõÆð»êâŠÅ^q—#vt¦ó’¼} NûåÞŽLŠ”Òjl[X/§ÝÀŒ¥¡!ÿ7Ô7I­;v¢›£ƒ–ÞVƒ,©t»w54KŽ!ØKãøÐëÚõYãÙPsÇŽ åc×.pû$¥yE­™|K6–„|·/;r©§Cî/Lþµ.N‡vdèÅŠ°#.Ív䪸ÐfóúEMž]œLïô>ÐìˆJù‹íÎæšºå(éé©°6 .v·³„GLæE‘+|‹È£cÍväìV VŠb]ýJˆMÉqÛÒu0ö·crQiUq^QK·»‹m…|‡Üù–°DûGo3šïnÚ*½Ü±#ØìåÅ×kj—C¼0t ¼îoÚçWÞbS’W¤’Eu^dÄ DñÆE«`¨`µ»ï`Øã•E¥ò¶ÎðL´ °# ½­G]@¤Öúº•GÚϲ봪º±¹¶QAL.&#ÁÒâ1OH0Üëï–VîØv“X:¨-)uè#«wJ+wìH¯‚M’vaL>¶æ^pÄŽ`›6ŸzcÒPhp·ŽL3…`G:o÷|$P€[—®ƒT—?¾ö>iV…`G`ó¼~v?[>0˜¡¿Ž°Úö¥ëP(߿߾t}÷p?ãKÀëÉu»ñ/$«rÒujIœáÆ—UÔooÜ{ì­ó3…àX\Áh[Ç*àñAlm´Ì­0÷ÔúûåtEآܱ# —N¼;,lÔUK>vž£ZÑÏkêVÜì}S@L°UÁ:“ôѲž»ëayž;v¤ E. lU”´ºh,’¯l~Ö/×ÁŽÀLýű·x6U/©+­2n•‚ð„ò5 ¡@/ºÁëù-Šã;bRQPºeÉš}—޲%Œv †Ç£oŽ‹BX_l{€ž\·KB4B°#–ÜpÕœ–Ìß>ÿs„YN(=¦ìÞGn²(Œú ’Š5Lnyù…5_ØÐO޼Êïü@Ü·|Óçð±· Ö¹cG,}?…k‡ØøjeëqæH N@ôPó”Hÿâ[*1@–„.T¦œ ˆG™žŠo¨ùá_±7±ºv9„<­7õÃ.èD_mæZSÍ;á,0„gdzyÉÔ;>"çÑÖnËŽe±þ™#í/¬÷,¡Ü±#¯œÞ{ÙÝïÐw/ßÀÖytGªäˆ±4Z‘ÙtB¬íxèÄ£^W·â±µ©‚Ë ±0‡4m?Úqž#Ø3ßófî ÁŽÀç’e”/aúßÞñ´T4!ØKoƹâWPR/Ÿ|—3¸CÌÂÃêꃜdGéÁU;`HH°õ¸ï+ÒY ÁŽ€þ† .ÇmK×CµñÔ6š1Ázn¸áè,Ýïï~_=³—Y^2uõÎ…CÝîÍŒK\PÈ_íû9[>VpQÇBݸ(£Ú±#X„ ǧ6ìÁ✸«4(D£‚~F#²5.¤±¢þ·"ÜÓë÷llh†NÌÚÖÓöÀés rÿÉý_Ç¿¿8ö&Û¨Pd;7ì½t”‡A ¦±#–›Öˆ¢‡UÅå„Ѓ3SM€™ ¡ Áõâ±7bn仩¦±¾´êÃÖã–‹_0”ivÄÒÖT÷ÐäË Š75¬ÆzžTUÜ sdbLÁ¶œ fliy]iA1½ˆBƒ%@9<ÈÔ‰.â‰-K×]躧‰B«©þ£plÖùGUXD•¥óe¾:+;‚r®¿Æ³ƒ]¤2µ»³ ÃÙ€èSMt –‰ Mˆñ‘)ÒÒ¬Â4*Lå÷ ßr@'1õæÄ¥Ävq5j?bZTŒ‰Ò‡Äâл¶Ðbº0ý7‡ýeL~ˆ–»ÔÑÉ Õ¼DJ9ïÔm¢Kç+;_Ï• êê<8÷µv†bB°#`4:1îÌ ¾zfÚž!cŒv šÂ¯F&ÇfÜÃCJ’¹¨!¦ž,˜ê(íÃ!’êæŒ8GLY¥“L{q©i{šá>:n«ìF‰¶œnèô S"…A"–÷rX¡Ø#pŸðîÑ<55-°#4Wø{µqmAJ!ÂŽÜ‘>ÛØËsm9˜‹T²¼Ùo Â⎹Œ8ÇlÏvÑÜT¶I3.¬±î„q®­ jŒo±±jrJo˜€zÉx’8θ‚CÿòÎx !ØKGgí,ƒL»7]éj&{¥ä`*ž”¼¶Æ×ù‰Œnlbœ…‚Ñb¾{‹Ê¶$ҫȪ ‘çpD)ßT8I¾€×Èø˜íë<ý]èÞbƒ)Í\[ã­WªËQ|m.èÂKO×ðø¨Ÿ#‘qa5ØãÚƒ`‘ÐCÇJøIÆ…5Ö\`G,ïµ5Æt¤Ü[l,­8%FJRQº@FÜ­yĎе5+[ îŸ±Ñæ;bé« ²=G<Â1@Ýê ÚÙª¤ª°œö# Àgjè%‹J¦VZhØãÚËöHs8)q4f-0ìˆ%®­ñ?¤ÊÂ2c?†`G,ïµ51ÛÒ3 q“’uMQᄌj$AŒ4VÖ“0!Äw FÆž•ÇmÖ°#ÞkkƒÈ!”%󃱼×ÖÄ·ØX:$Á»’ð€Hgü^A 0]W·Ò°÷rÇŽ×ÖH/xìd™@†ðÙ´AFÄ=w숥a4ÁÂD_k…ý(˱#=ÃWÄUY’ €6yQ¹cG,5ç½€%)/™”ÖXwÂŽ@Âë8o“½eÉZCƒDØ¢yÃŽ@—}tåd6§Ã¸°Æ ÅŽXZjõ XADÖÇ—O:”ÉÉ;2¦1&'—èKkv2ðÔÍOæíríò†ƒŒ k¬¹ÀŽXêñu=Psh6¾Ü;’l’p¨Kε5>-ZáC‡,4ìˆqm$¸ö5ï zâÚ…kn~uƒ 6yïMË;béLÝŒ‘2øÖXs±¼×ÖH²u~lÊDeÜPcqaб¼7Ôd\Xc…bGÔ·â†î6]XCŸåµ5ñ-6Eo à‚A_X·‹.DãjüÄ·ØX:#B6ÓqGãzÃ8Œ°#Ds‚ií¹v0X|Ù°B¿´éaúCÞPcßbÔ;vÄr¯­ñnjç/ãÂ+;by¯­1šÒ·ØºzÒÏ£{¨ùnÃt ÇŽ ‘½—>–Z›& Ü»ü.F÷Â0ƒ:ðs„À|D °91ƒ¤UÕK9xFÞ:À¯ÑÇ›ykCsæ|/ǒǼo´[vÄ¥9ÁŽX¸30â‡Û*…ÅN+$!D¥IÀ<~jÃã¨}N°#6ﵞðp´‰ã308†cG&¦'_?û¡×æV¯®].#µH~Ü¡­óÐðÝj=Ã/|‡Sz0Á=ùêÖ'9<Sö䵿Yµiq3½Ü/)w숥¡`IX•‘ùÆš 숥/ƒ3ŽD`g B­;aG ŽyÍHû *ïÛúJ)IáØ¸]?:ü¯ã¾„Góíψ–pì«ëR}bÝ}œ2&Ç?úM Çß»ûYÃS ÇŽ€þñ£—»½¯å}鮇ÙÇïêûéǯû"¥yEß½ç‹|öˆ-öî…8ôãÖïá?ÿþàËœDÒ—7=l˜¬áØK«EÎ[&i{ã:i™üýÁ_C9»ÝÆã þàåýòø[jŒÞzµ%ßÚñ4ñ­ó·ösÜѸáQŸe’;vÄÒöçiÅÀŽ`²áÁúÅÀŽÀ¬‚ø2¼˜p숥Ø*±œ;«ƒ_ Q–ömi{°#С{š¶°ms°÷hÇy?vÆ/‰N\oÑʸµµ+XMMSÙ gŒ:Éx2‡3½7e`GÊ Kš}Q8v³ ¯dÚÍQa‰Y]UÝÈlj}÷ؒثRÛ^íëT±Bv¤¾¬š!ç;owgnKpyÂ+l(«‘‡´t¦m`GÐé•c—i ̓‰Åâ•¥ÆÁW8v4ìdõ6±#©<ð(;‚.)û߇IÄâ2 v¢a^Ò/Ô%®£ÞÞŸœðFíÓÉ<Ž™R\ØÛŒ“_ĉV9üØ‘D<‘ðEùñ#èµeà?æ ÜÏè|$ˆ9ÍÞõà©æç+ëEØ?}æ±#Tn‹‹‘,ßÂrÛ±X]cT›VX” V€šòƒ’t5‹ùq!Ö,°#–Þi²c„AñsÔ7ed8&‚!Ó3ÓòZþíjÝ ;bééRj1Fºõʨ†^É”D1­óŒa¢Ûã““rŒ*{R*eËjbG@-¢ŽcrûÒuFk0Ž´ŸéHMTؾt½ß…™숥á#‡ÛNC²0©**ÛѸÁÏqN°#–>FÇ̳ˆ³þöÞû®ãÈì<ä@@‚ Áæ%’)Y²4¶œÇë™ñ|“öœÙÝsvÏ~û7ìÙoÏÙðí÷í„ñDÙ[’,YÁ ¦(‘"Åœ‚H䌷¿îº·^ݾ÷6 òmËÒÃ}ýº:TWUwýn•ñ†b-ŠÐeØòÎqmݲH>tcG”ƒG®Ÿé±} ÁÂctcG”Y ·.pšŒ9`,aQƒu”§û†ª:ìG‹"” $!ߢŽ% ñ-H¾¾ǃ‹×-+ˆhy?o¨¿ v„ÊTaG”qíËŠ0zZ¶Ù†8e¿é°D`@kÀß}M vDŸ6£ ˜YP1÷Á%ÂÝØeΪ‡®žº” ΗÁèv.ÙT#8û/aŠ#WaËY/µ]‡|ö ò ¾…ˆ^´Aqߥ#òØZ»–n²²« `G”ÉyðêIþ3_{ì65DYnìˆ2gÕ·Ï:tõÜ¥‘ÖãtbG¨Î'"…ÆøäÊÂæýTaG”1AOFåCÇS«vZªÿ3ûå»0½ (¬ëЦö›ï\øXžÑv.ÙmQÜù(o e{Wï²ÂPµõÞ{çüAyƒsè£Û­K-lØ}—0EôºceÔfJ°#Ê(—}—>áÄ1 øÐÒÍa£¦;¢LüN7£ E“HêÆŽ(sÛÀœã ÅóW<e“»±#ÊÜì½|ò=yˆ>·vOøRn\ìÕ‘‡/¬òsë± rPüå‰we,Tx~Ý#aŠãbG”Qgr£•–€+¬È0oÀtI¶¬zÁÓ«wYa¼”>,ßf…¡RF)–~eý£á{æq±#ÊœõÐSDv-ÙÓ]ÖÁ·¿9wà„¸É­gV?dQ„ýÕéß¶ve¯¾¡g_±Ã#6ìÛçHЍÞÚjа#4F¬#cGòÓù`Tˬ"ýrúÅÇŽT–”ïY¶5|™3.vD™u<~ëcGòÒéÍ V×ur„ŒÝ ͺçÄ‘äèõ³ú¸ç{• CÃ{öJûͦö[ ½ÈËÉ]3o™uÆD#gZ.û–¶®[^T c÷`üð3iÆ â"eŽ;¢Ì¬6u4únGŒ±¼¨¤~Öë:bäVç±Ì˜Œÿ><Þéé 7`½ ¹y˜RKŒŒÜîî ¡J ‡â‚Bhë’¶w¨f {CÐl"«ÿcúmçî>“#†(bgFøÆÅŽ(}Ÿ0¢ŒuH™7Ì#ýnìˆ2÷œ}Ãý~ç "Äx0-·£õž|ŽÒî×°—sÅ>S4£!ùVScÚM~ao”‘± ÐNöut¿Z¤‹ßQ>"ñ=‘këE”TZ€Üñ %’¨õìH¸|jìÈÔ¶Å]0 q.!%ª’m-B}Å4å®–ñ»æ ˆ“ãlyz¼Ötµ8œ¬ÆyžbÈI´JN\½ RäÖÕ2„ðÑ®—ˆ--)ÒTXJÅ*$ã4¨Ç1]𢩒®™÷`@‘ÈAÑbŠÂÉΓ˜Ë á¬ÎÓ9Æ(o„ãZ“ wk£˜ÅU Zü¡£—ì„H¿>•;šœw€r³LøÝ°¹~3uJp! g–| Šý>ż< " ÁÚ`K¸)’Rˆ{] ê &*Äé I±¼¨4Î ¼ü¦âÞ:˜8Ez ä"ß ‚S!¡rçŒ7Æ‘ÁÂtƒ" hqk`û<×¶mïí¤­í–Fwt¥ KâÕñÄL忳 CÈ1]±´•91áŸÔx'&² qbr¨c¾ˆ;³S¡[å¼ ¡»#º¬wÜDñ\ažû:qˆ®µÝW¦tLH縮LùNÛqÓ®LÒ–±L&'•Ê‹¿'TF˜§œÞý’¿x—ÞqëH+·ƒi„©”Ã¥ÈY5M)ßÑ ¼ÈöŸ½´n×êDýÂrjóg§3× l5¾?zLKùœ±#IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IùK‚IJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IùÝ- v$)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$åw·$Ø‘¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”ßÝ’`G’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR’’”¤$%)IIJR~wËçŒÉøÿJá±u²=tUI¥\Õ2ºqêL¨)ÓXJW‡œß”«ÿcºâ8­eƼ¦Æ«†Æð}N*'¾ójlL·–“ŠmÊt>Ûýœq(fÐŽ‹b&CýÏÑ-¹š3³š““Š›. GÿÇEwç E•›“Ûy…JºZ.šÊ‰#8ê/J:¾µQÝÔ(fËQgdl”?çÆÏ:Öð­£µ†š9NŠºÿºZ&7'Ç1hgdtÄP'Ž"µãuóàˆŽanÑ+wú rqý×íøÑTnü Ž˜^åÆÕ¡Ö0FTHÇ‘¦”>ç¦b[ÃꌌiŠéœ´£ÎhfÔï<ƘŽëØÐÈ0x ½ÊË­ƒÉ63–§Ç=]¨3:æ “T*®5ÌÏj:7¹‰Æü)¥R΋ëªáLBA:?®Žim}C—âzEuÅØÖG†°L˜.'Å1ô Õò5ÅØÎ£ZÃ|æëyˆ^Ç!LüOWn¯‚âfÆòÓyŽýˆÖ°Ü¨€j±G†™ ±@q­ òç¸Ö Ï{ëˆ ù1ëHHŸÁ`é˜5BSƒf róu†Ç˜ísâ8gPÑ«†­áàUÔT†»‹ˆòrÒEù…Ž:¼;|h(ŠùnŠÃC¨PO±oh€?äåçF-¦}pxˆÿŒkÍì2owä¤r ó¢9¿o¨_y˜*Lĉ&´Ö;ÔÎ;ê  j¢ZI~‘£v´^íÌÏÉ+ÌsÕÉ.P:³mQ§w¨O“Ë+ˆ«C»Œ>cwåDVë×=&ÄÖp´ÖoöZQç@æÄ©ÈUì5Ô,/,q×á?Ë K#«añt¡)Gk]=ø€ÍèP|h­w°J ŠâêÀ¢Ï$q­uö÷ðgWkƒý=Cý…NЦµî‘¡ÒübTsÔáϳŠÊ"ë@êŒx»äâv¦«g°";zõ•ÆH 4…P¡"¦WŸ’¢_ÅåŽéºÛ×…é¬V—;(‚Ÿ1ذnŠh LJâð ª9(¢†Ì‰´`t›Rq·AW䤈Ö: Qt>NŒ£N×`/}† à} X^PâªÓÛÉŸQ-ÎèèíèDu×aë«(^ü¶ гKfÅu ­uŠŽ:Ðר£ÇXX'p¨Ž XO±BÕQ‡ZƒÌŸUTGQ¥@Dєìjë½ +®:žb[Ï=þ ¢‘­¡WR|U—F·†^±ˆvèÓZ7*W—VºëŠ•‘ÕPgÈg‰’xŠwzîògÈœ¸1Þó)¢‚C4¡5È|Tp×—" (â(Њ¢rGa_‡ÅYèÒ½>ÝÿŠâ2‡…‰Ö (P¡¶¬*®lã»}Ýh°cŒ&°âˆGk gÆè¢H­AwT—ʼn¯!Ý«¬ÀœS6;²šQ žÀ„M×ÚíîvþŒ:‘†è)Byv{Fkö8Ý¡[ëíBßÐŽC¿@>ßíë„f¯,‰î•–®öÞÁ>›[^_§?W•ÌŠk b¼£· *ÛU§·sÈ?194r€bñ¬Hƒœ´?}¹ªñ Šƒ>ŲxŠÍ‚b]ÌT€\·¯Ñòsó¿¹ó´-„ª£*tôj™YURá8)´÷Þƒ&B…ºY5Ž:8Ð":î>oïÑJmv鬸Óµa:/ž"ÈA)ÀÎ SC°ÃÛ{³âkÞ¬Úè^Aeû³ZoÜêlåϳK*ãn0ÐÚÍÎV4R_§­ç.Ÿ& ‘ã(Þ¼—¥ˆaFä8˜°â¹8ýB­AÕB×WDϵFDÑNy¼-¥€! Û5¥•qÇ„;zŒÞ©DãZƒõr§§jJ«ÜQ íL˜b¬ƒI ¥V£Ç[§«ßc‰‚¼<ô-²ȵvw`µe•qu¨µÖnMÕ¶š¢1.¨œWçúÝþ 5{Fû;ð­£µsÆ’ƒ"Æxcìï®-›§ø¨ÿÙßÚµ»ÍD±¡²ÎAS ^ãœ.p $6luiìFS¾$t‹/h„Û]ZBÆÉg:AÓgÈ·8“ †ß;LÇö^6VS.­ES8q§*e”;Mp0Œ<®¢w^ó8Ž"¬YºúvlÆþᑱ1ré‹»èÃ#f•î¢7rÊœÜõ%­óÊ´_\CŸãnÈ1L°MN*å¸EÑÞoºÐó¸“/Égcœ7D;˜Æ²Þ¸1Jw•ÛAF®´tn¬ƒL ¢Û HM‘çÎÑ}Hy>æè1NÄ/Åhßž©“••)}7‘g ûyp8@ý‡¸·(Bl e²BB_sD _í:¢Ö2¦N¨c˜sÔ ²DÔ•Å<Ú<<$ÁIè|x˜Pcúl)dWQ~„v$·ÿ©h‡µî P,LD«Æ½ŽÇtõ÷“¬ÏxOçZ³JÞ,¹%¡Ú-Ûßö ° M™åÆyÛ㨾òî—³Šž‡)*º õ¹äÂ7¡ Ã}ãna€‘Ôח`œáËØÛí… Û ØÅuÌŒ¥µ1Tjí}¯7ÐcMW¤íx·¿kx${µös ‘{Âj¤1Î** ; ³4ñWBºÎ`ÖÝ‹9¯,*³8 t·¿{d4`»T—‡¥\wðŽ#ÎT¥ó?}®*©ˆ”æ4ž½¢<ÛkŸDט˜ÕY…¥Ö¬â[ºuå'˜¨ÈëcìGy}9¿bN˜"æ­#‡´LEq™u7N¾g®ù rK´‚KÍíÏjË]©gÕ^G6ø¤ [<ìÓÅöÞN1ÆŒžüÒŠüEó†…$Ç\UEQléjðð™ŠøËÐ+í7ùs]yuäY‚®A‰¿ ò æ•G«nuÞa$ &!Ì«cKW»qi{Ë .­+«Ÿs:ú:ùú²(]0/æþâæ½V>'TÏ ßÇa‹aµîð ö,øÐš.È®ÛÝí†â×CS‘wL×ïÞfг£ê€â­ÎV^kC±°¾¢6D±¯¹³M L4éœ8{û Æ:òȶÁ1›ÿ\9gq¸Žò/qè3ÚYX5/²Ú™–ËÊ_¡…Uuáy¬2Æ8 ƈí3oV­%¾À3ò> FÎÜYÕ‘§èSÍùó¢Ùõ‘¯Þmf1®Œ« ®¼&,0¯´Ýèñ·mmYUøâjñƽ¨!~ž_P1'Ìù` º#PFÏ.­^î9Ê¥¶ë|Ò®-›=·<‚bSÇÍá b˜ÖÖFlF>¡)s]yswñÎ5nmnyuä5:*\¸sÿÜ4e¸ÄàÕŽ[£ j3 |irãÞíVq׃9_R½ |}Ü=Ø{¾õ*ÿ¹eÁê0Ee¤DsçúŒF–ÏYYíÜí&¾¢]Q»(|a ž¿ÒqÓ˜>K,™]oY&`økw[F…ÀÄ&š\#| î’ÞD¨³Æš…Ö^­Ëm׉"ÍDÜÒêùa{3Æœ «!˜—`é¡-0X˜óa™œn¾Ì>°x½Š*§š/±-ráÛ=MñÎuÈU^ë’üÂe5 E¨¼“·.ÊéÂ&Bµ0ETëô).¨œw»÷Áå#ôúvݼÆð=¬Yq6É@’,©žoU»ÚÑ,EÔñòÚ…‘"ú·—>ñÅxæ¡e["{¶GƒôºxCýòp,-"™  ¸¦n™%¾ —0órk£ÂšyËÒ6Þƒ7côz¶¨j$€Eu¤ lœ¿Ò²…@ëLËCÑkªº´rÕÜ%E´ƒÍ(O|5 WàÛ ­WÊk 2pý¼åE„§ƒc„\Z]·Ô¢ˆMm(Ž(¿¹Õs—Fš|oûÈû”Q[VGڴ؇®â?Ÿ\ù`¸ÎµŽæs­Mü'ú³bÎb‹",Þ“Í—Z…Ç’dmݲ°<ÁÖøøªGÕ¶…kÃ/Þ¹~©-+TA,]å[}ýôüyûµaËvã'×ÏÈ2Ô1Ö1ÜÔ¦è}ÆNlŒÚŒ(¿:õ[þüÌš‡Â ÎŽÝ»&BDC†Ÿ‡/ÌÀ“+°Ž0Þ<ûa‡¸ÉÁÉ Ùºbjê¸õÞ…Cò:tó‚UÐïa¢¯œ|ÖÕúòÚ=a#–ÿgöK4$ºôÔÊEhÿý—ÊËÉK6Z ßBàœv{Wï à q¤ýå‰wùÏ¿ØýÍpÏQ`$°e²µa 5²Úýíø3GXZ¶õÞ{íÔ>>ã ¬˜³h÷’Íá›´Ÿû !Q0càùíQ– ÊÿóþùóWÖ?yr„Aû³ãoÓçúYµ‘úåØsRaÎZºÙR1ƒ#C¯žz?ˆV©ƒY7Û7ïÝ~åÔû'ä³6Q¤ŠùéÑ7¹µ‹ÖíXds@ñå“ïYŸ[»Ç¢Ùûʉwj“1›š(Lª •éó‹Ö‡V06ÀÖuâóë £+>¼r ûˆë|cóÞ09¨3ìGþ )Ë E˜%D1ã·ö•õZa/½sþcyÅôÈòm‘Çíÿôö?ðçom~*|*„:{íô>O‡’KkžY³Û¢ˆ³´ž¤øØòíÖÖÆ·¿9wà„&å…¥/lx<¬Cqÿá¡×øÏÿøä÷Ã=Ç“Zýy|Åkkƒâë§÷]l»‘ò½Æµ¥U{Wí´¬XJ¯žú-_èÍpl´]¡†1bÉa‘ÒlŸ–°Œm7˜7î¶Û$+KÊ÷,Ûöœ¼uCeÈÕ”V=º|[xŒÊríf¹ÑÔʹ¦#•WN¾OÝÂÿ"m{h´£×ÏêãžïqYXU¶´•¶sÎvø5e¡w€8’Ÿl&[B·¡®ƒ4û˜¡hº¦Áv‘2f&Ÿú…ù Ïfµ©£yп:ÆK Š*ë¬Ë½îÞ[wÆ2cìT‚õyx¤‹/ªT_1'ü¶$ÒÞ»CYÀGª¸@ÍÃ·è˜ >t8pí·ÌQœƒ†$H.ûãU 8<6âCm¢ÝUô>ý©_ÏÉ)Î+²¦ktl¬o¸ßwWéöÌk~¶k•ßr¤’£ô«¡éÜg4û&Ð@"gÄó ëQæßqä³/§â}ßC£Œ_XiB.~~½ß4–Š{{?àÔŽ ¯@N(ùE8Aë%`«L=v$®ÁHÆ´aGˆùÂ?̉ •áÆŽÈ@²DE;"ßì—%Œk;‚-=ÇP»i¤Ë‘š V£’¯%…-qÜØ‘!! b*òrÒì)ÌGx„)s‰ÉskàC²ÛT0ia;‚ ïÈ(›¦Á|ò-yʤÓÁ—!ÁÇ|Z²@â[Âw\ìfžßƒ”C£+ÜØzQ•9‡»†e©‰gµx0Ø‘îÞ‹m׳Óì½µuKY£]ëh–/ÚrW4Te±'›/J`"—Æšb`BpΨiƒg ŠoݼFK‡º±#PÇÇo][_hdEíBËŒ™ì&êøÍóDQ  ¸²v1»0;z;¥´á‚ý¸aþ ëá”`G "HÚˆ’!ŠÒkr¦åR[”0Ö‡.å§;røúiáÍÊÎÙšºeìu€²;|ítøÄ›pKÃj&`†‹w®ËÑQA;kÅeè¡k§$>ƒk¯Eÿ2ŽÐa°)ÐÚ¶p-«Øø7î¶„Và yzðêIŸb îºyËùúª œ#(îX´Ž)bãûï8fdsгáÌ)ÁŽ@>”BvŒu+}‘“ãæã«4}5(gÁJ òá¸Ø‘·.Ž=¯Ð¶aMêÆŽ@(Ž*ƒkÙ½d“õ|J°#`B¬cøW„ÒðQÓ±­­—i¥×ÆÅŽ\i¿A·çV¶ÚÚõ·½wñpö`%¦vÛÂ5¬×Pap@¥0¯ð‘Æ­lÈ%$–ˆ ¤D+0mØqøDžÙùuŽ­«ù9fvÛÒRÉÅ1Ÿ6Ô¯h¬µYѹÙÙŠu ÷†Dxƒ»±#°Bß8³?̘ս«v²ÙÔ~óÀÕ“aŠõ³jv/ÝÌþæüÁ;QùöEë~ãbGÀrkó¤A)?$(¾vzŸŒ_ÂÕ±L–µpŸbG`÷¾qæC‰Ž¥ÉÈËÍ{´qƒwa`¿qv¿²*™óãS«v²yüñµSž¼Ö燵;rínË;b¹©ÊâYϯ{Äjê‹yëì‡M:B`¹)ììûÙÑ·Mð•€âÃÒ|u㌠‡ ýá•cÞw¢"4ãÞUöÖvcG Y^>ñÞK¥´ øëŸä]pûþ+GCÚXÁÞžZH$yÅcX[{:±#„õB6áï­̺L›NìÈ[g?Š<€.ì=úŒsÄ‹‡_ëo_PÁÒ¼°á –ù—Ûn¼zê}ú,í/¨¼ßßú%ë·nì_ÿzèÕÁÐta¢~ë³|~ºåÒ›g>”ñõMOZ¿ucG`rüóǯDR„<´ÎhãbGþéàËòZ’ËóëåŒ;=?þäð]nAnþŸîzoq0y÷üÇᦠŸ‰7vûÏÿ&{õEF÷G<Ï¡ïpÌ SÜÒ°ê±å;è3ùáá× ÇŽooù’Yd\ìô4þ¹`»=¾"Kñ¼Ü ÓчqÐÿ°@Ï­{„u(˜ c…ЇÙ%•ßËcãBë5Y>mš¿jÓOæC"½|âÝžÁ~þ–Hj“cåNë3ØÆ=/‹ïnÑo—‡/a¦;ÒÜÕvÍ(Ž”WÅC`T—…'nìNg—Û®úî”Ú»IÎ׉½|“Ã¥”9¼‡µ­;Š­úEÁ 7B4q* ¿U8Ó°#æ=ç^ëõ~ú7Œ^>Ã0Ö7ZY¸÷_̪ôFaY&4ý"2`ó´aG2*ÃmEÇL圴åãŸ*ìHÝ‹_EÕKà#²L1vÄÝZx…¦ ;‰öàÊV‹n숕’%œ,ÃÑ™#Ðí¨ÆÂ‰$ÜØù-ašxaE†G):S$ŒÆÎSàÆŽ€¢±º¢zŸQ…ù^˜Îq“OéLõÌÀÐ`Æ:2ú¥".8onìÈÀÈÐH”KXDN¡±–@«o0_BûA·0Y´G°.– $¨ ÝØLWï`˜"•â|âÆŽôŠ dV×8F(v…LÙ=Úq:GÀp¢EæçQ ©H|IÆC‡4·;Ò?4À­é0èÀ¼M vÓe‘éʾ°]F£`UÊ8À,§£;‚ˆžÕ Ú±FáÆŽ@÷Ë(é"›•àPýÝqëˆ%˜e»§ ;žÁyi,,1Íßu&Kð*[ LhŽnìö…|¯WbG”¾^™M’SÚ‹VÁ^ã—rÐÔP¢E™Ð)Ö¬º±#÷ú»å¦–MaÏÎñÇxóÞmÚÚaIQU<ËÚ3 ;r§»¬%.Ø#Ö:N v‡ ¾à°f sEצ„WÚo1¢%Xücå¯qcGüo­Ð` #hÀ~´0ÁñÞP3 ;ÒÔqK&ÑÈ–Œö=Ԙ䭄XeyíBË€qcGε6 1»u³ª­%pcGÀ‘¨e˜ÐzAyJ°#×ï¶°çÏ*` Š=0:6v¦åÒH K4Tε{òØÈ^Ì9#Z¬ÝÑX».…Û{;Éo.°¬VÍY,­¯éĎз–7‹ ´ ]›BÞFºK©¬©[F[ 2䦈/-KA:½¡Þ›·3·/ka%¿Âè7vßò­¥U —VÏ 8ɦ;&¼ÒË J×Î󫇯ŽÄ+ã´¶.;&.;tõTèàuLH›Öˉ["c¨c‰™ 2yìv½tBK­Z;­'ŠÇnž‹òÿé2§|6 aŒî£+ÇeTYmãü•daBYG^ÙgŒðàâ ôç‘ëgïeSZš‚$!_T0yq"g r€ô2XBȇ@ÝÂt_~rýL”õ¥ È‘ÀŲ.ávDǼu˜¿tì-_‰ƒRÞP¯«}]XÇà×Ùy}aã–;ÊùéÑ7{³-î^²É ±öÆŽ\h½Ši$€áÁØtwúÞÅÃ<«Þ® ŠO™‹Ü¿–E{+B5XLÜØ‘—Í·‘#Z;¯q§±…`üÿäÈ[C£C‘VÎsë¡6qL€ WȘ£Çw·=+N'väÇŸüº-J£¡lÓmliÃŽèo½Ùx^:ï;[¾DWL`›h;Áv^Øð}þÁ_d¯_‚ËôäÊ,åÆŽ@q„ æ^A;{qˆ“Ëßô³ÁáÚƒÉ>·nu~wcGÞ8³ÿTKòU™pz*ò‰;‚£Ù¯Ï| ¢ æóOv~>ƒ%ä©PjÛÍ VøG¼<ðrÜí›!tˆ;ò£O^—Imäe(ì¥]æÐÙßó×ü$’êþÙ®oÐf¡BÃÛ±¼°ô/vC>qcG@ñÿÝ÷ãŠzWEÛå˜ã ¿ÒüÊ9_ßèA…À„=}JÙØü-™Ž·:ï@"¥²ˆñI¥¾¹y/é˜gZ®Èo9EÆœ²j°´ìç´aG`lÀBã¤0;‚¯™»Ô’½“ÇŽà0 ]F˜vÿ[º«qcG¼Û3áIåY­,*'!†1âǯµKìþ¾2ucG°ÜƒÚsh„þNÈ8Ó°#86 ¶?φۭ̽ñ%™0v$e^§îYY­ý Þ|„“Lv„è„:F +iû”`G9tB¿åÊWU‚‰/Ÿ!v‹a5þyaGdБ”ÉÏ4„tYœêÀŽ )ùv)v²ÑÄ:f»±#ž!îÒ±zä«zÄfBaÑ[—'$•ƒŽa–|Œm†ÚO™ÎX)ÁÜØ‘A/ñ ùwsÒ9é!?k@Æ@:ˆ¢”\hÚHޱ0O‹'2Ý0L¥…QþÐh6Ç žÁì~Õ7”M—P˜Wròz«8¿³‡ƒŸ‚Ð>„5~K?3á¡4ÅÞ¡>žU“ý'Wæ¸aMÅ>à©6ÁT †˜ѲåKs`GL¦º>ñm±5œò‚üj€bDPQ½"pæ )“ #!™Åu0F´/âH68:L¨‚ Eï(,•ÛÄ¡L.ÜB ÓÉ‘çüò`RðÉcG°aï Ç^±Ž=“+ÃHRÎæ~?»¼2 ÛHf „¨ ÞK:°# (¯A1"'fÀ›ãÆ~á nìH[ïÝÑQO°@èÿ]oõR‚^Œ]R¬(. B‚jJ+ƒ.ÀiÂŽÜëïâøÿèÀìâYzÞ°RŽ—µ¥«‘I¥&öŒqfdó@Zv¤£¯‹ï. t·¯{Øß”ïÓ„¹Ãl¯£Ý¤ódöúª’YXS, ²Åa÷ú §!FæÍ ¤)q`G@Çf¦ˆoÁ2ó.ÎXY, O&L¨ÚÒÊ®Á^¶ç@k~01ʌŽ@Ì^3ÇT$:Q·x£Všø“ÇŽ˜ ÙËå¹å5X ˜ÃÁ <ÐÞÛÉŽ™tn.†&W ,!ã('vkáþ34",Y—«³dö|PĺhŸ«ÿŽÓQsgSÄB['ü…˜c’7&´ÐiR×Ó Á~µ !´oÝk½ëû8ñóš²Êë-¬ÑÀÖÅ–;™À—J½‹g׃mØeKÑ;$*×Ê“AÂñ-䛼¯ÁIY=yì(Ê;/ZYy_ƒ6!ÓÀ DsŠ.5TÍ5Œím%yìd‹Œ–¬)æå›HÞkMÝ2(Ö>àK˜®¦ö›l{à‰£xòØ‘k: M ·¿¼vá嶬Cñ„îÐ?¾z’“Ž ëgÕž9n@waPDO;r°é'ä‚Á »yŽ)BèAw@èé t_¸caŒ±¸PæÊó̦0¿vÞ2ÈsÞ¼„äŽúèÊ1¦ˆ‚L ±Oͯš³{Bïˆï|RzG¯hîj“XØoEz˜1öÒúyÇo]7/X…±ì¿|”G„åCͬ¤Êèylm0¹ôÿá‡Í]w8õŽ»–n¿O·\⇕Åe‹gÏ—Ó…vÖáP“ÇŽà+6LÞ¨Gý=•1væÚºeýCãu#“A¢ü0-7²uázÄvx3ƒà#:ãŒ7Fèz+ž¶;‚]Æ»6ϺyË —Fk'4.š'¹Ðz•uÚßÒ°æøÍsl g[¾]™LY€ ¡j?l:>âä:ÝÌBnÓ8ºÒ~çX¸mᚣ7ဂÕDp¨·Î`ŠKf×ã‡jÜÈÆù+ Ç@H«Ø¹d#èuaL>±âml V¬hs~ðêIIqWð|z°#0!Âcà+tõ°Æ[¬’æLÃŽ¼ñŸ§°‘kî¿r”϶Ø–ëÔKœö½q8²m7,ÁH8á%ƒ`gl¥;ròÖÎb(nþ¨é8rãqó¢ö/¿ËŠä`4úPÝÙ‹ÖKóýˆÝûÒÑ·yñUiA‘µ‹!aöðCŠG‚'}[vï Ç¿}f?¿sŒo¨_ñîùƒ|…v †dÇØ^ÞÑhùÑåÛŒ`ï4ƒÐO¬éýcG~tøõÿ]-Ûk°è<«Ðõø§c&È@ 7uÜò¡$z´ßÞò%Øð‡¯Ÿf †ÄÞ•¾wáǯ‚ܰ´ƒ;B~\þßžom’ÇŠïlÅ’w.|lê WÈv¬ã;ç?æëP¤2ÿÑÏùüš%!Òà7ÓqÚ°#P,Cpø'à ŸLÁ„ßÛþœ¼O›6ìÖš-‹«ço¬_ñªÉ8C¤¡h 1`6üÃ_ðOZº†ºDm¾°áñúŠ9`uVd8jA½1«³ðäûüž$íÀŽ€"Ö‘ÿ¢–ÇjìY(HZ-E3^û{Wí²ò*/,±¶‰;r§§r’mðäÆi%ù~UÞ6»±#»ÿ§lkA‘-¨˜ &ä {Øh0]þíÈü“ç×=z±íš¶ÍôãOw½Š¯ŸÞDZÜjJ«ž^½ г¶Í¯œó­Í}äÀŽ€â>y]|û4lchL5ÖôÏwÿ~íÔ>ÖhP+0! |³*s,„±üÕ¾㨖0éç”Výêô>nü™Õ»e„E7vF «è0´6T Ov1Œ[üù×üdpd˜° ;oÀä¼qv?ã?¾¶ñ ,˜œIqæ}fõC°{›¼[ÁTA^Þ? Y‚ÀjT ²Ëñ$¡ç¿O5Ö6€É!*rôM¯}¥6Ì_A÷áåc =°”é´aGpš0·ÚÅÛ~ͼÆóææ„|.x²+ÈpòØzõ…¦¢0×X»èrû~}¯¢Ÿ•”XrØ<¿Là~ó5òØ)úrÏŸUzÍ Òï^ùðçüʹÍÿ1DµÂW¦ìN…z­}¸K]yuöwôSíÜTŽ•^|FaG´ƒ kç &í Kåô‰—0·8ƒPÿÐ Í`ŽÉ¨Àoé੤ H;‡ø ÆÜœè,*ÅDa±WMvÄ :BW»£2ÿÏMåXn÷ÉcG¤›>'œ~|Ó4*½Íïj™JìÈø‹\ÌiÃŽŒŽr'@…øFÂGB Ab±#-•£sPyÑ)$i øp`GÐaÿÎKÿ‹$‘Laƒ®Ê¬(n숄©æiÐI¶â°H´\˜Î7(Šl$dò dQèžå¶ÃŽèL4EãkL{/vÆdø ]è‰ÒÈ!¦H“áÁ1ßžÎÕ‘”о—ø¡dvÄ (²0rPA 2E4ŽúEAO Ç|bpc²%yEY˜g>¨`º‚vÄÜú€‰t(RÞ®Pfü§;Ò/@!xNáOÄ«ŠÚ‰‚AÉ'˜ÀÃVÖv¬No6N€~‚>`rxŒ˜^è*üŠ×‘ž(só«üÝ[ZP$Uˆ;‚ ”ï Ð}+êsû`3iyL;‚ee¨ FGž`LSDAQ>ÁfÁÉ"<ß1ÉŽÑ1ƒ~¦H—k˜.HeL}˺ŠÃŽ`õùÜ_! :ÉM{–¿_ªK*zš†¬2ÉV5EnvÚ°#-]D#c^ÁGÀzVýÕͪfÿŸ2¡A°³Àÿ=¾[¬+Ã>»±#ÒOŒ%#Š2lÐþáI‘LÉŽÞN^°yY&à ­£ôßã‰ämvë%g‰bÉ0LlÆüˆb8?à tÄà°*5ڌŽ`øÆ£Ÿ1-Ѭz·*æØA§ý+{evد[çÉŽÑz‹ÔÁ¸øæz“\ÔÒ¸õ…€u`G [ä mäí3îj¯>¤¥CL;‚ ¿åÇ´€ì][×HõYÀÎÑõ«Ï·6õyÂr3ÑzZÜŽá4.À“ÇŽœ š²*ÈIp5½UCemݲÑ̨|²jîb4L`³™¹$½‰Ó†È"™1lLžéO®Ÿõ! °Dô'×ÏŒ „ÁœòÙ`B¹›¶-\ !#giË‚UÐ/—³ “ ¶gcÍ w®zâ(£ï%ÉWw@¼¬ŒyâÎK\n»Î»ckÃØiçZ›XÜ$§M;ÒÜuGúÕÈk{R×÷ _Ø&Ëj°§¸z›P¾MþsòØ‘·.°) Û`Iõ|(¸C"ÅÀ¦ù«rssé ÍØzÝBÙU :ñÄ$­u™>Iì6Ž„Úl^° |Þ¤ë{sˆ?ÁÛÞ“ŒÿÄk\9Î:ziÍ,ÄGâ ]ÕA“­Gë‰\Ñ8 ?±±[ÄÖ#§Åo/惖 ëÎO2æªOÀZtòð²-ØÖ0á™–KÞÖÎè¸âëë—A!å›K:2WˆIø Tá1:±™“ÇŽ¼y6™|Cý °+¤ )‘Œ9ø<¶|;žð­7˜o¯yUôã«'y£Í›U+½ÂìÈˆŽ¢Áã Ör«ÏÂŽÑ9ØDÞJ½¶PÁ&½ï]8Ä2a×’Mò„8yìȾKŸ°…zÅáÏ}¾k'c<@Š6Ž¿sðç©ótr•ž¡Kr7¹±#oŸ;Ø?ìéÄåt²õ³I ”zlùŒz¿xòøòæXÄËmžE ãjç’ æ‰CA—ö4ê7Ý_?½_€ª‚èxÍ[>PX/lx\>)-(úöjä¥coÑ»4cÁzñðk|¡'Í’Ew}[>²WLì4ÂIŸÑ¥¯™ø˜^¾Õ„‚ù÷Þ}oºsÉF<ºY ?¾ÿÀWÚtî›ìl˜îÐÄnž1¡2mب*¾uÁQ…8á¿pýŒúÒšÝ2ŸÎô`GG†þ惟òŸ0! C!êIeŒâÏw}]‚BÌR,ÁçØcP"òɪ9K j  Áâ…Ëc‘;b@!ž-HçѺüË¡_±D}èÐ9ôª~b–ûÚÇ™¿û0 :ùî¶g¥>r`G>ºr D‰I`öü‡_À‡þøÖ_¨Ï±•;bB¾·ýË5¥U¨Ï¶êsóS„¼ÑÐÉïmþ†@'¦,ߊmõŸß{1 :Y¾ OÐþ?ù5·ÿ—{¾#=¾ìÈk†âé8<'ÐÉzëlÑ}I>–ýooý€£æ:(þð0NtÝÿù‰ïÃ$ø¹0ãÿá‘ï¢Ðìl~7ˆ ·ãÆŽü¯oþbk_h½ú’ß~*•úO| úõ3ûü©ÿé±?À1ÏÄB¨CÑhˆ É-f&«Øß˜Ú£òüºG«K*~`°PTmïªa“ë˜L—>!hXœsºùÒÁk'=JnÞ·MÒ¥7Ï|x»§~ «O¾\1mØ‘.5—áz*ªêÐBÿð l{ ²}Ñz){'"3¸ ⥢¶¾b¸ôœ6€½ˆ!ëæ-—îväfç¾2@:ÚÀ"ï$ƒÚ‚€uÍøX,ÐMtáÉ!CðCyeêÀŽPôkšœ²ëŒ¦Ö×#^[:™Q©¸NœQØí êçèà,_c†•…ú°0½')ýZ;µ@@ú¥~GÚ¼•Í>ELΰ0ø½[A³’ÖUóô`G¬ tdÓmš0*ÊÄw¤'ÉÑ 9qH‘H C>’`G²ez±#AôÈô`G°ðcccÜ 4YØ åäÀŽÈ„5œ¡fDDø°ÒÖ8°#^ÂCˆ3Ôè‡þ¦²ÒÖ8°#VÂ2,ðp(ø÷S¹g8C ~8*"R :°#~Âå¿YUè?4¸T3âb…£ ótÇ$v„rHê'Í’ ta¥­q`Gð• ¯›¢`ÊÄüàY…ô„ •Š"?CM@QçŒi|L6rCY¾é“Øe°ÏüÙ‘ 2(C &AvÃJ[ãÀŽÈ„5~†©] M@ùþ=a-ìHi~1øsÀ÷Žc-èÒv »‡)mM·Æ‚øûjÐCŽÔR”—/èìˆLX“ö3Ôô‰‡y¹¹RyO;Ò7ÔÏ-G#âë~ŠN!áø9¹6Åà æPÄ‘ kÐ8©‰±"ìÙ",v)…0æÊ°‡÷¶Îù|ðF t‹-‚Od³Ó†a¯jÆxmÑ l«æ®;<¢êÒ ´ óªÒysØí¯;Ä]8–;°#VœÐ@ÑÂŽÀžƒb¦â 5҂ĪaVñ+~Úd¨Ñ¼g²Øxsb¥­q`Gd“¡f¶ÿ°[<¬æ„5¦/¶žÄŽX÷fv„LvešÀ®'NØó0»Ž“ÇŽ`ºdãþ†xˆ]‰HÏ1B´‹/¸•¶Æ_i@ÃÁI›Q†˜ÚÒ*/‚´€<¨¤d«T¬Œ3 ;bÖxIyt†šR Á}] Ló<„â»ÜvƒÕ%N§§G:°—VÏ—œæÀŽÈ„5˜=:qIìžÈc˜;"Öp†šæÎ;Œ´ÒÖL;"Ö€%¨…¦ö›ìt§‡À€f "Žn¸äØ‹g×K§ûä±#G„w¼±v!ç? >„x—‘{ÈsŒ ”¼Íâj{Ú°#üU†2Ô˜v=M‘ÁÖƒî!°#ÐXWrÚŠ9‹ñ™°†®eE› ôÚ†ú•^ÂC²Þ\—(ã­aãÁˆ8°#æ«Û|/Ijd+mÍä±#2a l$rÂAì7“‹"£®·ì@Ó‰Ñl Š¹Ô‚t¾‚ %²jòØ‘}—²~نʹôþý>á:B÷‘KŒfŒœÜ0*$²ÊÊû0I숕°†œ©˜@fϲ­:aM¿÷Ôë†ù:ºþ1ñ&=¥­‘.´óW &”¸ãÆù+±U/Š­J.4H [ìŒQ&¬P%ï6²xXOØoð~†´0€ÈÑ>T©÷)ìÄ•öÞÃŒ¶äw.Ù(Öp†ð <¬)«’#Pį_ϦHß±h‘¨L;b}µµa Q¤‡Ì'°..ù˜ƒÊ¢2‚@™20ÔJ[ãÀŽÈ¯@á©U»ü‡ÙY¥‡\Øÿ+ÝÓe5 ”%áõÓûXcZik&‘_q†~˜1¾á±“ÕÞë9Áê÷ìÙµÒûèÂŽÇ¡÷%g¨‘/”ã!äÕI€òœ ÙÎJ–öÓ«wÉ„5àÀ5uîC‰´aG¸)ÊPéôžØ}VÚšéÁŽè¯|ü%Dߣf£Yl¬´53 ;"Ö(ó24Vå¬~}Ó“²5vDºÐ àH ɇVÚväƒKGXk³cæóóØôœjÄ$»—l¢Ãã 3øèÍsT ˆ¬}È2äð¼¶l¶L[3mØh(A£æ2’3ožý±#ëëWH3lòØÊJS-Lnsò°#Öu;’½:K¥pæ¢{’+m7{ îá¨Íe^Nó\­ «êŠó‹Fõ•éUÆŽ,¨\™:°#tGMsƒÃ8=[ü×2Sâj§bæ`Gú‡µ/ŒZHçäÒ$c8쮢´5^ÂÓ¡Ât>ù|%vÝCÍ>Ý”WLÄýœÑ±QÏeòJ—úô`Gdð 97%vMK7úç‚Éf±I°#QeZ±#͸þt`GÌWvD§†Rq`G$D#‹‰”pS3;’Ÿ›Ñ`/êL;2ˆL-v$ QF¼rÀ¢(ìHM ÄŽä™`$üç±#QAìJ&‚A;:צ_èb=—I¬'ˆ±BŒ0L$ (á?'‰¡èüÂŽ€K;E ;ŠJbG”¹ÙÐ;B€’)ÇŽ¤sr¤Ó}òØ‘NP„±#½A@‰…10=F‰ÁYyâ°#>LÄkœl?ɧÎx_±#C#Ã"¥ËD°#üÊô`G ø+ÆŽ(DnýTØópŽl6;b}EØL!aaG(‹ ZʸÖdÐlÆŽÜî‘©ÃŽ`÷aŒÒËn‹F2“±#ü•ÄŽ"ÓŽÁC°Ç¸Ø,‡,ÄŽà9}%±#Åy…xxýžá7QÆeÂíÌdìˆï² `G  ¤Ÿ±#ÅEWÛo¹±#ôÿt`GNН;¢— 2Aìˆ 1Â0‘H@ •ÉcGdˆÆŽè 5~î0vdYÍ:]KìÚ FÞþ̱#Ø0ZšØŽ`"ÐrwÌLìdÝܲÙrãvDyw^±°#: ˆÙ8;¢ÌÕçáë§Gý@€ŒÁ6a îbG`pnkÈÞGO;‚ébß3cGtÞ_vDÂD"±#üÊÔbGø+‰«@›éÜ\º8–ØhÆã¾ŸLM5vD~¥|숗¡Æ/vd¡'±#йKkÞ ÂŽ(ãWÞëë’Ð0vD™7°ÇÅŽT—V.¨˜ÃE;¢L:nßÂŽPÄŽ <¶bÇ{ñÁ±# í[aZÂØˆi L-v3“6y %vdkÚ[­·|9ÃØ‘Kw®3hj±#¨/§M;²iÁ*ÒP;bD¦;Bm}ÀŽh€ˆ^M;kÄðÛ8Ø´pNè ÂŽ`³Ÿ’€’u{$vdyí" ˆ-±#h­Œ‘¾ÀÏ;»¤’Ø¥" Š3;B1,숙 v„a"‘€*ìH&‚¯ž` 3Œ” +QbG‡¤Ï v!‡µ˜8vÄ$jÉNxv¶Ÿ„>värÛM“¶æ ˆ10‘U;¢ô+øÏý“(ÂØ™¡&ŒyaÃã”äQbGö"ìˆüб#/Ÿxöw ;¢¿2Z[bG`–¿*4……i¬m€Ù£‚Ø‘ºræ3ÂŽÀl WùåC´ƒç/{ª$‹Áµï߸ ;‚ƒÆï˜ˆÄŽ( ùÿdÚ°#ÿE|ÅØ‘Ÿÿg®Ì ìÈ_îùŽ|H3†Ýwàêqy´!ìL P"±#°ÏiãH숈¬ã?Ø‘0LÞ»x˜wS;òµMOÒ™KbGB‘ aG&"±# (¡âÀŽ„a"ÊdÎ’½,ìL# j"±#ó+kw.Þ(CŒ0L$ (á?'‰i¨œëÃDt!ìÈàÈ¿ŽØ‘ù•s¿c¢IìÊ|BD&…ùަØâÆŽà(ôÝ­ÏZØ‘_x-;ò§»¾¦Œ$”ØÈê£7εt·YØÖ€3;ÂY8%vdñìùòRk°#‹f×KK{‚Ø‘9þeÄŽPÂksõÀŽ(cZØ‘²ÂR™2øþÂŽä¤r°Yÿ ÀŽô ŒŽÆaGhQ,ìH¡ïo¥2=Øé1gìˆvNgÆ>#ìÈXœ`G&_ìHà!•;ƒý,°#2‘ÍgŠ¡d4jJ±#£2Ó±#x˜…QÁÔ63;Þ–ÍŸ vĤ§Ñ[ï~ÄŽpzšû;‚é"{ëw ;IŠ v$\&ˆì¢cÉ¿;>‘S—`G”ßû bG(ÄH‚¹¿°#Ìó>ÅŽ 2N!v„/F§;¢ÌU&ž±±ÄŽ´êD6ÞâÎØ¸#ÿ¾œ5;]ŽKìX æQ¼?±#—Ûn˜ƒÊ§ÀŽL2î:ÃöcGtJTNd3aìHdzšÏ;NO£¢ÙHì§§‘.4NdCezrÖ@‡ÓÓ´÷v†ÙP™9ØHl@ÉT„–Þ ;‚±Ö8“$v晳æ3ÂŽ|¦9kÊ K×ÎHìømŽÙÅ;‚͈-ÎYó™bG°p2= 9S!7$;YØJO£‚ؘ4kæ- ç¬QŸYÜ‘ù•s¡ÁÐÀØX2½…ÑéiÌUµÄŽÀÈy¸qkdΚ™†Ù½t3T¹…ypÑúÖžŽpΚÏ;òøòiq$Ÿ vdŸžFbGVÍ]"“wLv«€Ãþ1-Ø‘–îöØÕO‰QËY‰‘9kÔİ#`Ë%³çg™Ê‡‰ÀB'²á?gvò2Fùï3ìæDÞDM;²±~~ÜC*Ÿ;âÎY‰Ù½dÓÐèˆöz±#PЬ›&ŽQËY‰ù笉Ď˜D6{^éi;ò²HdÆŽàWÎväËëöHÜÞ§ÅŽü欹১™8v'AÒŸ/vdyíB<üWÏ—/ì4 /E'Š)÷ÙP™†¸#ÄõÁ¿ [Ø‘ÿï×ÌÅõ§ÀŽ`­O7_:}ûò ÇŽ`—‘É!±#ày){glΚš’ ê§ÄŽà¼ Íu®õÊ´aG¾9kºz™ÁØ,c,ÂØ‘’‚"4kç¬É+”îÏ1gÍ(¹Ñ“¸#÷IùâcG1%…Ië»°#Q0‰ÛÀ9v$3Æ!²1¨¼´>œŒŽJ°E:7[ßA—ØI¬Œ7¿µ°#/輟,&ƒA‘¸ŠeŠèž¼#pbG2¾—4c/@ƒuƒ$@Q~a8ĈÒr0 (Á!z +ͬf¨ó¶« ïaãØ ÇŒ:;BÁH ÌX"P”Œ¨o¨Ÿù¤$¿]ê“éi v£fo:F$숲`"y…iF#>œãÀŽàW<«y=»tþ3oŒÐ£T ĈÁŽ€¢ÍÌ*,E;rÔ¤e1óƒBQA{L„§‹Tþ3þt;ùƒÅŽ`íxe1ÞŠb­Â{û™b~nZ%“ÇŽô ˜†Cþõ{" ¶(b8<ÆHìˆ F’å4vÄ1âõ™fÕF¢íËÜðìÙ",va‹`£õhäG?39ÌVLxŸh!Œá`$T¦;¢ÌYÝ›>Ø[ų ó °ÐÚ¹ë6:¦¥½·“ÆŽ€µªÅ¥;¢Œ‹Ž?võÙsLíCàtŠtܺ××ÕíÏ #Á¯ð[êiYA1­‹ôß”.pvÃáË2Ho¢ˆyãUK`o‹#làJŸSmi•äí…A ,;`$F$oö'ië¹ËR.;‚úàíKm7X6Ö”VT•ƒåšÄœ4TÕIñåÀŽ´tµûâ(±Fëxµã¯*cŒçZ›”ò„#ø ["H¿ÁqNRœQØ /1tIŠê94?À,å¹ÛWÜØé PNìø3bÄÇŽÈËwÌ¡ä4vDÂDÀçä„Ã1zYÎÉä±#á#*Œs>Á„C–ÒŒqˆ‰á`$T&9~ó›=ؘ(t@†x!/N8ÄHsç¾M†±D` *Ó†Áðikg `ŽÖñØÍó¾>ÒØp…ôìv¶ŠÜMëë—ãÉe±ÙévIbGL0’%;uCNôC×N3jÛD®‚;–¸êc8= X‚ÕÖgŠÉOço1ëxV'²¹G#‚ØÄü`Oue± Ø‘5uË$òcòØ‘¯žbØP9’V±#¨¯ŒWLùâhÛµ0ɰ:œfÝ´r™$v¬%FäLmÒõ=ñ…ìX´Œ¤·¶!&Ü`¼P;BÁH$vdåœE`lL }ØÚ°¶%{•TvícÿbÚzY3ÈÑy~áÎUz“æ±Y”ƒ;òú™ý#þùbCý 0 d‹0a[¡bV#°#8ÐíiÜ‚%cë]dƒ Ñ Q_a%á#8JHñõÄŠ¤í4=ØXeŸ\Ë"«¾bBŒ¿yL +¡o3 ;‚c£ß<¼LcA`´ï¿œ]µ¯ozR¶æÀŽ€ßX6rˆ‘È`$Tؘ‹œØ(;ë¢ï•“ïó ~[,÷’çÕmÔüüÎ…ƒ|ä|aãã8ÈCµ±EZœ_ôܺ=LÚùéÑ7ùê: réuŒäéU»PA Ì0v²W îGìØ[2É÷¶ë>¾v꬯t  dç"ÄÈʹKÈúGŒd×’ ‚þ˽+wÂB¶°#°ãyÙ1vÄ„á &بBiÉ|Q±#Ú9jôú¶?cõŠãxžuhÁy‰º‡ çÛ¤=˶Â*èì“îal+yRv`G°ëYþ×ͪ!¥€mÅ·@(ù«~bþÒ7µXbX>8V¼,T¶ 4Ô¯“ü¹ñ^KìÈZÖZÛøk ò þòáo+°Š5¨ƒús›&±°#þÆÔ¾;í0 ÜIÕ决Þ[ç0väû|¢ûèÍsT§ƒçŒÜxó̇·{Úé· (YbÚ°#°„Fi*–V/XZ³¦þ;>fìÈæ pòØèqÁB·O÷þ;9vÖ´´Øð’wÀL¥Jý·.Þ¹nF¤Ãî€1sºåûæ±;pø¢ OÆŽ,™=_z'Øz‰‘æôÂQß½=’¥ŸTÏ’î¹…Á´`à)C‘"ž°òÅ$è»ÖÁ~ï„.°#tÉÉÍæääèyð[¦—äñ«A‘×°jú°#c|!ÏØݦA³’ôä±#™ !ÁŽL¾L%vD#ŒIg~Ú°#`Ô1Ÿ ¢ºèØÄ±#cð€±OrseØt`XJBAJ®…½ŠÃŽ(ƒ™`ÏÕ “4d͘€¹äxÄ„:$¢hà‰ì¡;¢ €—@'hŠ(â_è9DfFFéÀÌ%$O=ãÐ+C(ãÊË÷Ÿè’2 À"‡Âëbþ,Ê/À<÷‹ ,$@Mx’ìÐPmýøaiAæSBL4è$7²•9 ¤¥ÖÁN*Î/‚’ ZZ¨ïÀŽ`JÙ} ž)É/Í3é”`þe$tµ8¯óÀˆ²¦a,]ý=1S„âLÈ»£Ø€B@Q(•TYA1V–c (}ñ]*÷¯;‚Y²††åÈ‚( EÎêä±#˜„{"çæ›ô^7SÄtæå÷ˆð$bRTÖ7< Uéìâ ) ØLò½¾,p§¢¸ ““‚Rsa*mv¥µ§ƒ'áW¥…%}]#>@ Of• Œ ñÑɪâY Å—ÑÊø/å6™6ìúÀyL°|Õ%•0jõ¬úÒunùl v4*ƒH¡;=÷F}‚)×ÝÁW,s090±½CÞ`) XBR¬*™ñØÚÝÁK®èìÅoév( As‘ƒ­•ÓE>+ÏôL£> 2ge$39Õ˜½6Aƒ•gvÛ‡f•omÀö·:[ÇDH éžZTX3o8ä¢`¡í‹ÖIý2yì¸E†üYWßx­£™¥ õ€¹ŒûèÊ1b‡í ñˆá°Q„'ËÅÛêjÒØe3lcù°"ؼã@,¡¡ þmÃüжRŽm0QF0K¬£K ŠÁ'˜RvG¦ó1FТ1ÒC4^]Z &á`‡XÐF#Îø1 @qÓ‚•¨ ! Û® 1Ñ¢ƒUëë—_h½Êx/Š2I(Ýö«æ.†IsüÖyO}gt@‘ÅÕóÁ¼£AqsÃêžÞÓ‚â®%Ñ`brªå’ÜãÒ &Qf‰ÙÒ€-ùpôæ9§ê€" kºz?l:îʬ· cüøêIžg<±BÅaGPÞ¿xØ?hhÚª9‹^;É!ñ°}6Í8ùØ,zm!—¶/\–`ŸY³ÊÑÇ“e@ñÏwöØ_à…üÁÏŸY½»¶lö‹‡_ãQCóÊæÀŽ üýG?çSáÚyO¬ØñêÉ÷ÙNh¨ªûΖ/¡Â?ü¥ç¯M¥0µe•X !£ÇS©ÌOÂ9‘Ó­¼¨ô«ë»ÙÙêZ_Øwë³ØhÜ`ª-Ÿ³’"®C»ùuµ…Uu0V!yò]Ïmcé&h´7¡ÑÌ!ϱ²òânÚ°#PúF8è©ÀXpðÁ±ôVçòGäåäîi ž*„^ƒ»õé‚#sÃìy­Ýíè$ÕÊK§ñCIÑ|Ó÷P9uåÕP‚ZÄy5`Q3 ;2–ƒ]Ê-K®g¨ŸÝUôføÀð·õ42#Uœ_4:6F§Wúe‰~=Õ+~˜ÎMCÐõ f!9¹…B>«éÂŽà9ŸÐ9Ù‹ÄÛxfÕr‚n÷ÉbG‚P„0v$"Ô…Ù‰8¢ìˆ,Ÿ!v$‚Øç„±¢ŒXÅJX£œØŒ2b4”‚¡ÄaGÌ·£ü.¯U8 7v‚ƒ½õ\² ‰DyQF2*Š$G"áâÆŽ˜(##ÜTJ4 p4o2ʈU HâûðŽì7rÇjtH® [‰ÃŽ(-þÇ2Y܉lŠ#‘P”Ñ+¯šoJæç› e„ºdìÖH:Ë q`G¬(#VS˜kAØe´£îɈLK$Š2ʈ…ªƒº¢YE¯Ø@·ªQf5zÒ9Ð#Ÿó猱¼-ô¢;¢ŒÇ—-ÎL°5‰¤¨Tî¸ÉcG”‰.·­œ1ìJºóEÚû:#ǨD$.ìˆÊFÉRô[Ë@óU—.øÜØýí`–s”hJ™«@’*2ʈÕy+ašFìš¾eƘúi±5G¦­ñ«‘÷:5§¼Fn47vÄú6G¥F…ÄÃ<Ð:bºdV¬Áø\gpØbÍwFÅs)<ÑŽD('vDyQF,Š~ø%ƒh!аªé¹Ñw9RxÂ"¯RœQØþ–ÙÿtNzaUÀõ8yìˆ ¦­I§‹Ö(#CDì–LŽ TòæÍQf2‡}ÅǤ!û‘Ht”‘{-,à­u4q;rlFaG`Kà`Æ:4ÐùŒ¾.§•²¢Œ$—ÿ´Ö('vÏ·6ñÏuS[Q\fíqvD™œ;rkCéskÐ Ö¼M;¢‚QF,Š®äõp>Ó|9UG‰H$\&è–sž¤9@áCe”‘pÇÖÖ- ‚§ ;‚rüÖyŽÔ7:š=m–Ó:ZQFt5q(]<»žV]n¿Á€«Æ»±~=9ªa4£lùËó-ÚYÄ{9°#*e$DQß¼H‹nòØe&“ÜÏÙóÙ¹ù#:,"©XÅJX£¦;202t(› D¥½Yõö¤H$·L”‘Œ]Í+‰DRœÒ¸S›É ¹ZÆ|þîÖgåµÕ´aGG†ÿéã—¹ÃVçqØâ“MMv6¡5²cä¢6e”«Ži´ã÷”¹µ{ñð¯ø9¶¶£•°F9±#*eD™[åAAñM6"˜ÿÑÏY7Qfo ¢œØ¥åä+­¾†•äT(arbGT0ʈi-_¾4û';_ ‹ë¿ÝÿSñS>G«ÅˆæWΡ´,V”«©§WïZ#â€*'vå¯?øI—ˆßL!Ø ýª‰‘&¢Œ„)f ÄÖš×Z^;õ[”dBÕðù/vCúÜØ‘ ­W_¹“¬1~gë3 f¯Þ‡3¯Á@ G‡&òÝ­ÏÐpàÃ> Œ:<2ì{R+ç,"Ô)áÕ8œC¾QC¾K2õÌOžsÌ*ª‡jÚ¦5•Jó‹)¤—iÃŽà4a z£‚¥MGxêþ’Ùó­WÑ&Á¬B—1Œ&×Pä X˨p`GPζ\òg›î—R¾÷³J݃Y…ó8ßòçæäÒ­#;«zVÐõãÀŽ ÀÍŒÒ÷9©œŒn*åGÚ(”¡ïÔ ÃŽÐT ]rücÊ&ÿŽ÷Ž·!fü‰~}ñZ;¬\¹³Èí˜òA4V>5]ØÌà!ºçýßrwN;¢‚ik‚l”®ª‰=ø-SŒQñð‘T²3mØeœA‘ß«`^%*nìˆzD+èˆ;‚.ÉSz )'Ð17vDCøí{•y{û¡G"HZAGÔxØeî…3Q œÜT. V+ôˆ,M<ù&ÐHö¶ˆ űfÕ1ø»U(èw~$"ã{„@è‘àœ¨µqcGT0ôˆ,á #j<ìTT¿ %»º¼•dèY(e}Ö¡GDØY 5ìÃSÉ2ôˆ,™PÐ5vD#+ý·š,ª¥EaÓä±#VèI—‚ŽÐç^‘ÝFH€Ùų,9àÆŽX¡G$åŠârKݺ±#ÊÜ6²Ì3–¡ #Å‘ahD+舚FìˆÒñá»0«6{e¼ #ôäÒí®¶1› õŸVÐ5vDC(±{) =KDQÔäØû…u‘ùt¸W*tD‡±BȦ`‰ò~äÐ#VÏ°ÅæWÔZm¦aG(ôˆ4¸`º,û~J°#øŠgÕš1 :BŸEè‘€’Ä1l±¹ê•ÅÁÆ1§ˆU+Srbi¤ ç:¢fvD&䨒ñ‚ŽÐ_Mí·$JƒK8èˆrbGT0ôˆRÙÙ……°´f%0ÝØÈÞs·›": :¢¦;–àõVÁHùÐ F•‚‹ ƸzîRËzD¨ã- «-6yìˆ2÷8×lŠžo~ëµLñã«'¢N á #j*°#PÇ›N8BvÚÀË|9IxL$–’…‚ŽÐg0¡JÉ  #LQ†Q¢ö¢ªy¬†dèk1\¼u÷‘ëgtð¼P¯`H°ã´Dx•@ÝÅU:è}ÆV•Fd¡ #ôY„ `G QÃr`òØe"[Ü ÚíT*LÐú “Ãóćl9+èˆ;¢²¡Gì¦ÐŽJ9±#ÊpчJ&*舚 ìˆ †‘v] +sžúÍ…ƒá“¯ö^ƒŽ¨ñ°#ʤŠ¡XȾ1+ôˆœZìë¾j¡G‚ýò‚ŽÐŸ\>*’¢tDM#vÄ =¢Ä(­ #jæaG”=biÛpÐåÄŽ(£¤Løq»„ƒŽ¨ñ°#2ôˆUiÜÆíàÕWÚ#0y%ù…µ£MÇáÑá—O¼ùÞ—tD‡QP(T‚™Ç1/<ÿnìˆ2 „E´âb+Âc;‚t¯¿ÛÚ£Åc#C"QœUTV¢8Øì ®îÞà¬èP(2šÈ Ö‚±†#jØPÄtya~|ìø°ªd–Ô2–í½Ö~¤l5òI÷`ïÝ H¿¿[]Z¶™ÜØeXâN÷]a3éÈXî© Š_on^uiE˜âLÃŽ(ãËiñrñd5;lh + ¦;¢L£ÛÝíR˜€âœ²Ù¥Á- žñè׃\šWQ6<ÜØe6l‹ S5•S?«ÖŠ=(óÔPA…úHÍ<ìˆò2×´É'¿ *æÓ´Ýìlµî¡°g1aH®;¢Œ´É¾%ozV¨#ÇÔ†ÙÕQ†%®Þ½%4ô§®¼&Ì®S‚Q†%š:nZTÖYoK€m„YÈ%œŸÃ6Ì”`G”¹ »cÂÃòYT5OR„¿ÔvÃBÜr`Y¦;¢ |äÚÝ–ÿ¿½sÿmë¶â8eÉ’_ò3Ч¶³ØIšÅÉ’õ1t麮?ìaö—î—ý²ÃÐbY°G—dX³<í,qűå‡l˲-k’º}y¨t€tC‰Àr ~I^òœÃs¾—§ÅùH òs¥)¿&Oý<5¶ ÏŽö-¶ÏÂêRJ¹›l5G^¥¦$ŸÒ:§äù“gÂ-Ù™;¢Œ-Á\¥ü‰©l5¶ wÄ"2¥>ƒEÈê:yô;›>Âfœ;9nÉcáŽ(>Òëâ©Yß2A-Þ-?N L$Iè6RÇÁQÆùòEù‘Ý×N+ð‚Ε™,­û/}OÀ¥É¹á£úýÑ«g‰ŸºÕæ'Ïù¦#Q¿u4–3ãGlAJ<\~ê_ÐB#L¬¯ßyê穱³äÛgSˆwË ±mPœ+ͤ»•µê©{åôù¢g™èôâ±1½Ú‡ŽÒÀÈ¥S³)ߥ:&îï?5bÅÿO›¿&ç¡Q@·Ÿß÷ÉôÌÀÛßJÅrÔWàŽ€xké^Š„mó×ä²é1væŽ(‰>2ÐÓÿÎÔÅð@t,Ü ïú‰gì)seþ}Dä<Ó¾yTk³$B†Ök¹#ʨõÅ£ˆØKïN_òYH­[K÷[²+iÎ'ŽØ‚P¢5ß §‘wgæýËööõ’x”_(Gt_wð‚ÞwD™ûŸŸüÃé;Ê8¢¾–ÜfõæâmªùÎ#äÒÕ·.„³Ú™;¢$ú’ðûg¯†ú¥3wDo'µ$ÞŸ¹œ š²gÜmc?œ½æ#¢ÿøèï.O-,Â0rÿZîˆ21{—>ÃN†èf¿ëŸÑÐ,Ÿ=þ<õ Éüä\ÈBûåŽ(s#=/Ñ»UO†O±%EicûGçÞõô§ã ·õÖö¸#äï™O¾¹#ÊHBPtMqx¼>{-uw”ú¿æŽ(cüîÞÍÊÑ`æOÍ¥ŒLŒ¥O~îßõœ£‘SG€›‹wZÉ,IA…¿ýAx~éÌQ†>ò§…;¾s2oRù59˜ÜX¼ýàè— þôâu=õ‡Mq ?8{õJ°ÑÞ$wDIô‘b¡ÿg—><¸Þ$w„# †DêC&›¿ÆwN>_ù›/>óƒÌùG³ï¤¶¶£8¿#V(¦BèïÌQæHŲñïÿàðÅ"LÊ?}ø7ŸfÚ4Jí—º ;sG”9×ÿö_7Rˆ?¹x=ôtæŽ(cä`o¤>ñ‰#¶ ˜öT˜0ó¿¼ü±oóÔÏSÓç‡ÞãÎÜeè#´Ö:‡ÈbÏÀ¯¾ó‰Øæ©—§¦UlþÍøë;¿wGB[RÙjly-wD?O-ؽ?Ÿÿ(…ȬnÖ·ƒ3#V‡½ Ñ•;K÷±©|îVè'¾ço4V2’ðE’êÅR"Η¦Y‡¾0A LÜ­$6À{Óóá9ôMrG”9`.Ø/”’à [ìÊé ½ìX¸#J+…̆Ïaåœ+M…ŸÎÜevdzõ—‡‰Ì~´?\xüRç©©zCÔ àÓÃã¡Ë´3wDiÅ·½º½é_^’ËfYó¡-ñu㎨ $—1…1¦:àÚ=¨ûÜ‘lFG0ýðqS5ëû{þÑ>c¦‚þ‡Áô7ÆQ}$F?îˆòè#þñV •ªô q$(ÿ5wDyÌÅγÙzIñ AÆÿÔæø¼–‰ÒLÒ‰Å_71JÓðUšªuÉO¬o‡ /A÷«+ÂV±M5m :ëØ¡GXÉÍáV£bW¦UD/óŽx]ŠkJÓGô]Fé¬Q^çÕ¡N—£;Öeª‰ˆ>E&LÇ“ªÖT‡®Kœ|:D;±Tóµ;OÏš‡–ÖClåú1íRGœ F×HªuiMúJ¿óÔÔ½êê„Ø0—,é¦$fEÜoø6hÚȳÅf× fCR‚-îÚj¥Möœ8«4¢;Öh˜Lrº)qVA´¤"&=—͉ˆVŽÛ‰5ìŸ(¢eÙyˆ!Ö=FQ®+ºŸ,"ês¿¡gµ;Û ÑMó›Õ]½Ä1DtmÃZ²¦WâÊatzŒÞ2Ïgsâ5É!æÒi•<Ä–Ú¶œ*ƒÃÐX¡d‹¥:šÓYœä1šLRûûæzf5ŸM3´Zˆô¾…˜K9…¥¦oÊiiw왓§“1µ½öaüÏz^Ó”¯F6“-HÔ+ÕºioO±Ñ­“óåÅ1¦Ò?ÅL=ƒ¸K[†`› ê[‘ö b.Ç<ˆ»Dš¢OÙŒ1£j»^s”©B®¢%9DÖ³½±‰õÀ¬Æ™U^¥FÌvÓ”ˆ¨/j¥rhötDRˆ2A÷[$B)³ž]ò¤e1¸ É–ª¦…µ–„/QjŒ:/•Y`…l7u¸‹2,“ö-å]¹ØÊÑD´ÄwÜ›ˆh*Y]öxÌÛ1)ÀD*€¸³W·+0<á$ˆ[Î[-Zö â®CÐùË„D…êî«I"rÚlYñ<C½E±ó nxŽïR@™dާ…” L¶ø>Žá8"¯›Ã‰¾1Wè;JLteDÞdã@§K+ô†[\‚[¥YGE‘üÊ‚‘WiÖ|¡?‚Èzv>Ç|_ÈÛSFëñ-ÏI7UèE´ŸŒÓ”ãl!&"š¦Ä•"'v»‰XÔ©hm¯ž7' ´Ûâç £)‘.­zaΔ î²«õ>6l¾g8²$ÖkÕš‘9ôªØÓ'n4W:2má%ºÙk!ûÊ–ÍMl)÷±þ‘7±Z×ÍPlVލ†–fUìå³ùÁž~Q˜ ä&Ô¬7öúº{iJT ìYš¢ZÞ$ã£5‘¦œÇºJ•ã¶ÐlŸÑ¾Á¢ ¡)ã% ë(½g+Ίù8@¬ìlØ%ÍBêÙ³›µ-þòT±w@T ìYÇDò®ãJ•6§­©NŽ…\Ue”#»c«^ã)‹- ›Ù ¡ÎpOQÜÚÊxµ’ŸÍ=ÎÝà¥ôý…ñ€ïå!î°+Ùbl q£!Fhͦœ(ô"{Å颕­u&cî7š½šLìkí&*ú: "É©Œˆ£)Q|¸¦·wõûK#¢ÀSšb¯1WlšiŠfŒ‘Üo„ª¨CÑe ÞUy!)Ä!:j5cu(c¤NEq‡ÑMLˆ Uõl­ÌTПѾ!šÍãò&ˆ+t=;5:R=l¹í]6WšŠ!>]+#Éi ‰Š0¿ KÛ Þs¾r1_Ù^,ô#ÆiJ<æ¸Û›†ð_ñ/F7uÏ–R ÂÅqY¿`!¾¨Œ½„$5v8†œõ Ÿ1rÄchêÕÖ:OÃäž® ªÜ‰‰¦B¶½E|ì!¾G\Z±‚ž-Gb¦ãÝòãÍZk£qªmTÛ~_r™;1%ž˜€ÓiˆM4¤9ÚòèÕ3z…}‚r™OeÇh#šÎ󮩆øõˆ&*¦uÅÏâwirnH2«64¢þ` iÓT Ñ„YˆÝ8Aä!T—uŒ u†ÀO…ššàe’º>{-¬£ÌÉñi¥L÷è6楨CAdº–ÖËõƒ}^â”^"+yѤ¦µ‹0¶ÑlŠ^d§* !Q¢ÑžUÊ•šöšrf7ß¡ Ò^ß•k–M&c¯ÚM_`l‹3ä2*ƒhŠ9îù5·í«ú4±‰ØÄ¶G¢Æ¨ æ“B{šÈ`}‰†ÇÏe{Ë—!†ÄVÆ*+ÐøŽzb~¥Eô†öä˜@ÉXp͹-Ì*vŽóÈñEçÞîþ<8<èÖ.ÓÞ˜ËÔ^n3ô*)°níl¦Ë¸Çe/:SQOü*±H2“ï~Ç£!:é 5ÆÜŒÑÈ:„«l(ªi¾Ví ;h4MÁÌè`h$ØÐX±]Gb!rŸ¥‹îÙ(­»(‰ör}¼.ömëØ|ìš weH4pßôoíÀ(P-âArB»ÁoX#‘ò»ºÊ^endstream endobj 219 0 obj 2479 endobj 190 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [181.8429 674.5331 183.8354 690.4733] /Subtype /Link /A << /S /GoTo /D (Hfootnote.1) >> >> endobj 197 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [216.1237 660.4755 218.1162 676.5256] /Subtype /Link /A << /S /GoTo /D (Hfootnote.2) >> >> endobj 204 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [106.7225 110.7118 179.6838 123.6633] /Subtype/Link/A<> >> endobj 208 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [106.7225 99.464 189.9404 112.7043] /Subtype/Link/A<> >> endobj 182 0 obj << /D [178 0 R /XYZ 100.3464 764.2205 null] >> endobj 183 0 obj << /D [178 0 R /XYZ 100.3464 727.37 null] >> endobj 180 0 obj << /Font << /F20 186 0 R /F21 189 0 R /F29 193 0 R /F35 196 0 R /F18 200 0 R /F30 203 0 R /F36 207 0 R /F41 211 0 R /F24 214 0 R >> /XObject << /Im1 179 0 R >> /ProcSet [ /PDF /Text ] >> endobj 224 0 obj << /Length 2741 /Filter /FlateDecode >> stream xÚí[ÛrÛÈ}÷Wð‘|ÀìÜ<ú¦”R¶œ’˜TRI Ò²–½ åËßïôÜA u,{K[)U À ƒés¦§§A°5lÁ˜ ¢Ò‹RKÂ9U‹ÍÝ3º¸5çþòŒy›"¹Õ‹õ³ŸÎXµ`”Ô´f‹õÍBŠ’PEáná•‹uûïåËwë×ë«Õ×}özo+kIj^+;Z} Î$Bjà±'LÉsØûþØõÇ`ÿt&Uþ´tQpsïRÕÖ”­Šš«åy¿|yö«ÂlÛûÍq»ïW×JÓ¥„ûœ^ÈÝ…—ݪ`ËÊ-ßÛK÷ýÁ´ˆJ,Ûí(ÝÐõ›îàš®­Iw¬ð¯ëzwæÅùÅ+·W¸¡ å²é[×~qå ¡Ö„® Ik¹T®—lÔKã ¡EiH¤Ru噘Þ2ʹqÐÜâ½yìfØ «BˆåþÆmÓîúe:Å+Ó©ôÑ4Øž¹<î½åÞÝá¯÷áJ¸Å¬uU/Íó*J'7²®¿áÜ©¾ªšÈR-´âDÕõ„¼¼Q‘[9iÜøÅÍÀjRÒ8f”ô (ã5)e].´¨H)"yü±É»xã¶k8ùæÕÃ:ydƾ;e¡¿8e™FYî<„23Q†ƒ&ÊLˆ¨aÂv¶2Ù:²9‚w BÉYg=Н¿þÜw¥Øù'8Ú`ô&Gëir´D-Ç”9)©!–1B9åZJ™”˾Øì†Ö°º¿Þú(X¸avqeZý¨Úû»®îøÕ;·×lûÙÑk&V?&¡K8™ÆGî„3q‚ƒFVT]¦©Š¬ðœ•M{ !씕@I¤C._¾ú]t”~zçJ<þЈ}AéÈ­:FŽ™¦ÇŒtÌ€&:*“ŒQ³èžŽkCGcU| #6^¾y~ĺÃGÃ]œ~†1.Kª~X´ŠýÁ)ɬ0Jrç”Ó” ˜‰4Q¢ ºd‘Èq³í5>¾ï†Ï#NÖ/Ý6µû»D•¥qUú {·Û`jI5‡·³br{1ùh ]°§Â(‡ ú0-©çÿrê?٬ɮeš­Ù…£ÙSV“Ds1¢2+LOÁ œVM ÅLŠÂA“¤(%¥IRe”LM{2°çÎLÈCPn'³IQ ކîý._aBÛGØ-€æ áºiÝrw/¾IŜƺ4«Ù›N¯uÍð{Šò“UI8››!s+D~Ñ Ì‘·*r³I:½­IÓišPØD›h’Šh!ëHSZ?ß»’¶f0M7G>¨m´®ª‹}(oï D¹³TÞu6ñgÚÏvß…h¿qWÞ»5vkÁ¸ª~?¡3ddf(¹W02PØD›ÈŒ”¥b‘Œ´z6iÛîz4^²¹4PP.ãT 4Øa™ØunÌixûüüÍ ¨*±ÇáùgXÈÌPrw`, °‰6±ÀJR›£È‚Œ‘ËåÇÃaJî~0¼ˆ<¸9è«êÁ',`ppqíƒi¹1Lúz½¿IvWk}ƒo¯¶&=žyÆó™êùܘçQØäy6yž|¥Òœ¡¢çˆAíöÁbß7;P»²K˜R§ù?hÎ5mkóÈm2w,„7{¦!l¯á>f&ü´þ&ÐV ™¥ÉEKàÞÊ? ø‘¹‰‡¨)QTÏi-7ôíf´†ÃF­ÍÀF­‰R-uµ¦£Ö†îæ>ŽÃ6UÈ8· ÎC¶Q5;¸¨µ«gþ@ Œ}&„§Cw»½|mZÏþ~õÚέ“ªkúC¶27-öþ”jӂкTsjËÌPµ»9µ¡°Im8lR›¬ eR[Õf uVÇ”u'Ó ´…)Æ…B?±4¡°¦ŸÍ~ðkÛXºË ÈÒ¸ú,±Õ]€{-0ÂÓÏp™¡äÎ`lš6q€Ã&„"¢¬"UÌt·Ÿ`^ H\OâËõÝÄÛöáþ¥‘á–•OSnJ¦Ø¬Ü23TnÁnNn(l’›ä&LNS³Ln|Vn{W<Û¸¼¤… ZeËu°±oÞ!íºc¬LØïÖçoÿöÆ´)#윈cRLÓâÇZ!d¯TÿÉ—Áœ+RJÎç„–™¡B vsBCa“ÐpØ$4ÆHUñTìb íÚ×A ³f°«ŽbTŸ¿A*’Vh UŸ 1e™rÛíºÛƧgâ‘X ý™a%3CYÉÝcÆà$+(lb‡¬°º2ø<{y"+vàßîî»"¼ì²ûÁßñÌ–%{?Üî|–cÄ“~­[ž~ê¡i…¸>>4îúÜ sýȈëqØèúØäzƒÏ4O/D˜ ‘· 69O‹Àù~‡ëíî…Õ¨øëoꋼ‡QJÉ•z̈»6CPf†”{ #…Má°‰ ’AEzIÂt±6¬~n†¯ˆL)[ûÚå㉞X6šþ¶ ?åõfuáÖPžôzxÞ¯gf¨×óîc^Ga“×OaÇßÊ„k˜4«z^ºÙI<ê‡/ñ³î¿{Ñîðô»9úî…Þ\ïg>|qU&ñx¾ä? Ïgǡ٘k+!ÿÐÄ„ F¤ž­˜æf¨à‚ÝœàPØ$86þ„±’hZúøcÓ?} Ÿ½xöDYýh¾BOgøÊÌP¾rÇ™ln’/6ñ…Ã&¾¨0;•§+|øòU%F/Lílqú‚èuzi=ØN‹ îeI¬ZûwÊ×—Øy”bknS”%ûlz?Ì™¬P.3§bT"˜¢bf¹&à-,'ŠÕ%þ¥§f„›àćžÁ,X¹Ï §?õˆ÷ €¿J{Qúendstream endobj 223 0 obj << /Type /Page /Contents 224 0 R /Resources 222 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 227 0 R 231 0 R 232 0 R 236 0 R 237 0 R 238 0 R 239 0 R 240 0 R 241 0 R 242 0 R 243 0 R 244 0 R 245 0 R 246 0 R 247 0 R 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R 256 0 R 257 0 R 258 0 R 259 0 R 260 0 R 261 0 R 262 0 R 263 0 R 264 0 R 265 0 R 266 0 R 267 0 R 268 0 R 269 0 R 270 0 R 271 0 R 272 0 R 273 0 R 274 0 R ] >> endobj 227 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 690.4389 199.9121 700.0072] /Subtype /Link /A << /S /GoTo /D (section.1) >> >> endobj 231 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 663.3418 444.9908 675.0313] /Subtype /Link /A << /S /GoTo /D (section.2) >> >> endobj 232 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 649.482 347.1704 661.1715] /Subtype /Link /A << /S /GoTo /D (subsection.2.1) >> >> endobj 236 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 635.6223 369.1098 647.3118] /Subtype /Link /A << /S /GoTo /D (subsection.2.2) >> >> endobj 237 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 623.8837 196.0794 633.3308] /Subtype /Link /A << /S /GoTo /D (subsection.2.3) >> >> endobj 238 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 607.9028 395.5644 619.5923] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 239 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 594.043 394.3523 605.7325] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 240 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 582.3045 362.928 591.8727] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 241 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 566.3235 425.0796 578.013] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 242 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 552.4638 495.9258 564.1532] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 243 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 538.9146 266.6249 550.604] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 244 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 525.0548 495.9258 536.7443] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 245 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 513.6268 265.8977 523.1951] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 246 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 497.6459 495.9258 509.3353] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 247 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 484.0967 272.4128 495.7861] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 248 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 470.2369 274.4128 481.9264] /Subtype /Link /A << /S /GoTo /D (subsection.2.4) >> >> endobj 249 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 456.3771 357.1402 468.0666] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 250 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 442.5174 445.2009 454.2069] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 251 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 428.6576 404.1402 440.3471] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.3) >> >> endobj 252 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 414.7979 468.3221 426.4874] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 253 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 403.0593 495.9258 412.6276] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 254 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 389.5101 216.0491 398.533] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 255 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 373.5292 495.9258 385.2187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 256 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 362.1012 227.5643 371.124] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 257 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 348.2414 461.0191 357.8097] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 258 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 332.2605 419.4736 343.95] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 259 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 318.4007 495.9258 330.0902] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 260 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 306.9727 264.6855 316.4198] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 261 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 290.9918 495.9258 302.6813] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 262 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 279.5638 264.6855 289.0108] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 263 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 263.5828 495.9258 275.2723] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 264 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 252.1548 272.6855 261.7231] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 265 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 236.1739 495.9258 247.8634] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 266 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 222.6247 224.0794 234.3142] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 267 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 208.7649 408.2917 220.4544] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.13) >> >> endobj 268 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 194.9052 458.3523 206.5947] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.14) >> >> endobj 269 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 181.0454 402.8068 192.7349] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.15) >> >> endobj 270 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [153.8444 167.1857 469.4433 178.8751] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.16) >> >> endobj 271 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [112.3897 142.2097 438.2787 153.8992] /Subtype /Link /A << /S /GoTo /D (section.3) >> >> endobj 272 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 128.35 337.1098 140.0395] /Subtype /Link /A << /S /GoTo /D (subsection.3.1) >> >> endobj 273 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 114.4902 359.0492 126.1797] /Subtype /Link /A << /S /GoTo /D (subsection.3.2) >> >> endobj 274 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [128.7534 102.7517 388.6856 112.32] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 225 0 obj << /D [223 0 R /XYZ 113.386 764.2205 null] >> endobj 226 0 obj << /D [223 0 R /XYZ 113.386 705.3641 null] >> endobj 222 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F45 230 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 278 0 obj << /Length 1158 /Filter /FlateDecode >> stream xÚÍXËnã6Ýû+´”âð)QËIœ)RãhÑ¢íB‰[Jdmþ¾÷ò!ÉIDwÚ™i ¤ÈC^ñžÃCÑ,¢ðÇ"F)2•Q–JÂ9UÑý~F£ tþ0c”hF$åy$ M¥FHôQ’¥ÐW ý©ä>\íy´hfŸfѧaB¦I.…Š’,Õ„k%zVÌ>\2 ïDrš³¨xˆrN´  Þ.'L¨,*Ö¿Æç7ËâbYÜÎ/~œ]ý¬^Sçá•8L2Ù¸j—±”d CE2ÆL`AäORÆdž(JG…Ìó·»ïuÂ2X±¦ù°ÊwSæQÉöNÒÞN‡IcbЧ`PÏS8äÀ¥¤,w<©ž§íŸê‡vÄ’Œ¯~¾\Ù†ªm×w‰¼Ü¬~øÅj5¦EÑoô/øGìøµ`g ²3NÕ4;Á ž×!å1;Þ\ÒLƒˆÔ„„=”s¯PþÕÒý¹åqS`G-âõö7ÊDÕVõ=ô›¦;©º9üÿÿUUm{ή– [ÓXȸ¬×öÙ’A(Á`ò-¨Ž™Ä5¿‘RJD*2ð&̹}Wœ’Λ=Îñï[¶ÛCã”Ñ<زõú«!5è·D#:¯%D6ãÌ¡kË{«tB'ßTf)X¢VRžÙ’Y32“2 u2;²7T1"¨òÔñ¯MÝòÚ–Åõâˆ9‘éïÍ•_é ®F° WãÄMs ê¹ ‡¸É”s"UwÚ¬†ˆuÙ•I×íöžÇÏÆ'˜1qÞo|¤mñ|D pƒ£wÎ3Ó¹·¸1ŵ}Àúm\Ïí žíC¹óó5˜ˆ+‚k8²‡­“ÐÆÙl*8JRÉ¿Ë.þò¾o+Hû¦ú” G°  =ÎRM 2Ô 2r$4¦*󊔃"‘Ýrýôì} ã%ÁÚj›ºi«5 ÖH“kŸaŸ‘'>iÛ×V»-JÛ`Œ$³:Û½Øv”#~`ý`m«²Oö%lý êÏU‹³MòáWs‚,ÈÇ89Ó|ƒz>Â!{>TžFµt|¨×|Tëú@>ëœ#@M»Ï·1“Öûø]é>·/ y±¼uÙÝÚ³>ô ë+î~=aFư#Gé™d$Ô1r"äÀˆëSý—Q:0Rb»ÏIi.7xù¡Ö§éx3`£¶Æ™ï±g‡C׆!h/k +Ÿ»Ï†ºm7šÑº»ÖáÖ3'9å®dSD"Äm¬)#ÿ¸üÅjÙÔùÿÅmÿ#WP¡§.‚((Q‹ 4ÎË3l§‚‹bJµg6ˆ³wcÙÝ}òÞùò®sØK~ñycwÎaÔXÙzqîÜ5Ö_'¨rùÅ<øõœ`b r1NK§Ø€QæG™+ÂÿwéSèô„s=õÓŽÌ –Pp9t0ssŸ> endobj 275 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/wouter/texmf/tex/latex/SmallLogoInGradientBarTex.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 292 0 R /Matrix [1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000] /BBox [0.00000000 0.00000000 703.00000000 64.00000000] /Resources << /ProcSet [ /PDF /ImageC ] /ExtGState << /R7 293 0 R >>/XObject << /R8 294 0 R >>>> /Length 295 0 R /Filter /FlateDecode >> stream xœm˜[Že= …ßÏ(ιÇygðÂJâ©Ô0‰oÙûV]¥–ºÊ.ÇIìe{eÿzçTÞYÿŽŸ?_þÛzÿñ¿×¯W~·ÞRÙûýó¥¿ýx­\rêåÓï§Í×ßßÿ~ýz£/a£õ=Õ\ÞÊiä\‡~é{÷]b#{ÿå?¯¿òï—o mfÛî¼îç¯ÚðŸ¾m­áS.‡ þ–Ú®y¿ÿûÇ«¼ÿõš}c³ßµ–TªÎ>ûiÖKóã5›íÄqꮩ­Oš‡Íà×ö¦u™öX5Ò'EǤ÷w]–Z™ÍÓ&øUsoõלe§aÏkŒZÉÒã<¡xø3'ßh*‡X¡9ý~ÕcpÁîˆÒ˜Êï|½Ù­ÙRȦ]¿ƒ) 9[2ÛºwR€Ü³Y5àžç™üæ]Äké„0!XŠéi³Å‚O ×ôâtŠéå¡ÎûóÖÐ]1CȦF¶À‡E¿ËVÏ›š:^èa’'C¦(6ÝûÝ!;‚¶O¤Ób±t¯ðPâR·e-×ÔàSU:‚H®pÍ)µ§|ÜããËͼ̷fÿvd ©?¥ávœ„ÒózÙ$! Ëj©]rv`›y7ú]½Xü¯Å”Ä«6ÙÔô¸kÅÔäµbêCÈÂ홦2h@Ž&j³x}}£!À ˜ˆùÝοóvÀ}ÕÜ {÷ý÷wÍc¯cÕ7šÐ}h†ÅÌÛ €°@qŒ2sÑ;çÙæwѨò÷9¬¸Õè¦K¿A”ËÆ+fh@s÷ÈoïsÈ>u•Ã){ªÌûØeцv—ÏÆ¼¾°@çXÇŸÑ!Ä8 ‹ƒ×,O å¸éA¢>Q‡âÇ©è+íÙ=)Oß(èÅxkÁ–ÂëWÍåVħh†¼)ý±.?/M×Àˆœš¢ù£‚`¦’Ò)ºî"€üìQF6°Ë‚ Wª€S9x¡nÕw]^N]uÞc×.ÂØ’×y &Äч7zfä—ì„À`ç·iô ¸ŒÏ†Æ‘pšcŠRøÞ). q¡òð0‹÷¯Ç_m 2&ÎG‡×ŒD""1 ÙbMf4ó6,\}€RËÞ3YÓyÏ`‰‡†æ|¬ÀÃ{²Å&’¾YM˳£C X*1yëo³RÅN`^¸ý¤NDôm¡!0>Pš¢špnÚu³¢t¬<Ö}ÊJ²=,T’Å=¬2ülÐÒÁž%i°&yg¨) fÅ/á̶¤‚¸¶[öäéׇ…&Û÷¸‚vâS͘d¸øÒ Ó-¦Ò]ÈVñÁÀ8…í±œÃÐiX±5ìÅFÙƒrð–/™çI¡)Ú vQj„MHReD­•LAŽñþ½>?4XP“E8«3ÊCcõn´z Èÿ[¼ë.;ÞrÜš»xý*õý2J}½d'eËÂć»ôÖ(vI™ ÂßêODÈÏiåŒk–ò^NOú%›“ýÈahÄØ=Zò@:‡-1å¢:öò®-¸cÞÑ@…¯ Ý„íê‚‹)UôI½žªìpЫpø9rŽxSm3D*–t°Ÿ—fÜ„Á(}`5œÃõ ‹T/. U/E|S;ª|) áu ï~"Ŷý~ci“a\_;{“ÆÃp¾/ò¶¦ºãèbgo±¨­n°‹Ç:GÝ%SkćF}¦Z;Ðé}&Ht™¥Ë´c¼jKâ *Mt‚p( í 0ô$Yí~F‚VÆãô/¶üÃä{ùóÜ–fc4U´vŸ49Ï¥)ƪ©æ‚8èQ E0Ÿƒ8hÀ(Ó¶@‘fœ^Ñ7‹!KD«§À4þî–³³¾>{’îËýn =8ºw5Õœ§ùÄjQTZqh4‘œˆmˆWÕ)³¿ë‘ûÜî¹ýAuˆ:äöÏçß @ï4¡“\ôx*z´ör>d4yËŽ©iz"êÃŽÝb÷|nŠâ}UŸN_;ÝgÕtѬ^QÕª(s*qX¬à.Ù‡°£”Š“v” $øàYâC×c°•+A6 ’ùW'^ÿ>†™N2ÚøÐtÁkùëÏaÔ4T|×êãÂ{”—¬§.‰ðy£‡Lɳxâ±|—— °=š¹?õ)$åó©Í:€~(}=1‡nõ·¡óý[ÛP+Ñ×êÿÙ‚Rendstream endobj 292 0 obj << /Producer (AFPL Ghostscript 8.51) /CreationDate (D:20060104161306) /ModDate (D:20060104161306) /Title (SmallLogoInGradientBarTex.eps) /Creator (Adobe Illustrator\(R\) X) /Author (Bert) >> endobj 293 0 obj << /Type /ExtGState /OPM 1 >> endobj 294 0 obj << /Subtype /Image /ColorSpace /DeviceRGB /Width 2921 /Height 143 /BitsPerComponent 8 /Filter /DCTDecode /Length 20674 >> stream ÿØÿîAdobedÿÛC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YÿÛC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYÿÀ i"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ôš(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ JZJ(ïEè\P84Þ€2rh:äҩȤÁà0(©Þ’N‚•3D€œb%3Àõ©eqQáŽ:P±ÜÀv¤V*XzR²Á”f…BI-Æh˜%KçœÔ¹Ý>Õ×®8ÍI·‘í@!°}Ãõ¦Ï÷–Ÿ!NF9¦Ì¤°À&€è,ÌU8êj.c*Àõ©¥MéÇQQw*`(̳mΧ[±ÉSÎ)Y%Þ£9§A\³pMÔbÿÇÑ¢rZELàRª·ÚIÁÇ­,ÈÛèɃ ÈØÅ+&r9¨ð]^BÜŠ–8Ù¤.ãíLÙ*@¹ ÞÌÆäðM  ”ØÍ=à>JË´ˆ’I*³®Ð{üK;”ƒ#©â™vŒÛ6©8ÏJ’hÌízŠcîS!¢Xä ËU›£›|úâ òå"2à/z±r„ÁµA=) lÛ-¡jžÖ1·Û±WQ ¶Ü1U<¹‚¶pNs@2És%‘cÔ©¦Ø©o÷¿ © emJNÚmš2DCîôÇÔ†÷þ>#úçWªÜnÓ¡U$ãëW(»(ißzO ¦Éºæí£-…ð©,ctgÞ¥sŽ¢›,rÃre‰wüiÐvŸ#0hØ“·‘šdò©©l h•™Æ»S!Åû¹R“Î(º_Ç£þÌS-eŽïî‚jKÅ/lê ’qÀúÓmc?còÜÎAõ3ö¼±IpÎw)~) ¶ Í×i©˜n#G€G•b9z8LVf>­´ç´"bA¥ÿ«“ëUˆkÉ¥%ˆØ QVôèÞ8Ü:•Éî*†{y¤òº¸# gƒ@tDúl­$,¬I(zŸJ‡Nÿ¹¾‡ùÕ›ŽþŽHô¨lb‘.egFPAÁ#Þë¡Ék«ñâqúf›mpð$ñ“»`%sØçÖ¥¹†h¯Ä)¿ÛðÅ%µ›²LÒ­ Àþtgr¦Çû?Ú¼Æß¿5ÕÃζñƒ·x±ÜçÒ›ä]y_fòŽÝÛ³ÿשî¬R„nhÆýsHVvjZ×Q6û‹!㟦iuøÿ·ü?:Ö ¥¼73&ÏAÓ´O ¬G F(1–Ç‹×ñç?ýsoåTt?øö“ýÿéW¬Ê£$£~*ž‘[¸‘ làj:”þ$gaõ n$g#ËRÊ?§‹ùF”Wqß¿`lóŒf•í®­&™aŒºJ ‚p J4É?³J&-¿ü1HÍ&S"Km:9&EÜGô«7¯õO³—+éùf£[[»·‚)b1ÇÚXŒqV.­ç·¿ûM¼~`=€Î8Å“·ígß-»¶à¼nqIü‡›ñþU.•k$FI¦]ø‘!k-!FÙÏÍŽ:S)'dYÔãÆ_ þtÍ'þ<‡ûÆ¥¾V{9f#€>´Í67ŽÐ+©S“Á£©_h«¨ÈJ¢ÿ3Sj“4q")#~rG¥2öþTb  =êmBݧ‰JrÉÛÖk©MCYÝDGÖœÁ¯.åRÄéK3Ü\FÓ&Å@#Å:Hg·¹w‰ +ç¶qšo¸lWN¶r À€¦ýTͯ qN®rÄÔñY7Ù7Ä>•†âUŽŒª§r( 2IÝ®.R,¸Ë4[Ê䱓 ãê)ÓÁ$s¬±.ìcŠ[{wc#Ê6—cë@õ¹VhZrçplUÝæK"Ç©SU<©Õ ;8'9«žYKCäí heú–ÿ{ú €œÈå±´d ³f¬‘Àƒ»½@c–&uE%Xc4A|öû63ógö¤Á„ÆàçpÉ©>ÌßgÇñç8¦ˆä•2í 1šR[¿¸¿Zqm–ÀŽ»E%Ò³ Ú çµ;fëp§ƒ´S+©_F$ rMO!ÝoŸP*’íàæ§‘q´sŒRN Ϧj «9<Šš%>VÖ¨ö:‚€dôÀ•´Y=i°}Óõ§¢íé°‚ÈÅÌŒÜô©"bAµ0«#£ ÓãR£ž¦€?õN“îþ4Ô9$S¤¯ˆóíLÁÆìóRò`Ó0ØÛŠ~r™¤N”¸Âb„ Gû•Ž#‘JÃ"€¡­I‚HÍ+Pö¤íš^Ôœô =((=((ïKIÞ–€Š( Š( ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤¥¤ ¤Í©;P“ŠÍ'qGñP–ŠhèiWîЃšBÁzÒ'zI: ~xÍ u'÷)ŒÅ DŒÁzЬ¥GÖAšTâBqåÀm½èf 2j3þ¼Q7ÞÇ««tëC8RÏ5âqŠ'ûË@\˜OJbʬp:Ón>àúÔr×e‡pƒ&”€GzŠçî­Iúµú ¨‚E2lç4;ª ±¨Wþ>$ÜÜ(=8 .N’,Ÿtþ*«„9ɨS‹²Nh›þ>“ðþt å’p3LŽU“;sÇ­9¾éúU{>øP>¤²N‘¶ 9ö§£]Êr*¤`4²îçƒÖŸdNvâ“&I•Ü ÎEÌ‘cqäö^Ûþ>¤ü# רa‘žŸ…} QȲŒ©¦ùËçy\îªöÜ]89þtùþ?Ò€¹mØ"–=Í6)VU,¹À8æ‰ÿÔ?û¦¡±ÿPßïä)Žú’ê(ßi$‘פ2 ÌÜ6úÖ|*)ËrBñša'ì€vßý)Ì_Žê)h$ÙïK-Ìpœ19ôJpÀPvƒÅ:0ýÀFOZïbôr,©¹E1n¦1 îÕWN'|ƒ¶(ƒþBOõ4ûeEvÎ¥H²ÆsƒëQ_Ç£þÌTvÄ9ˆêb˜_Qí{ ¾ÒÄûÅN\Ëç+ŒñY1ª›˜¸ƒéVíI:sg°lR“,A:N LñÇ4—)o·~~n˜[KÿW'Ö™«Ë/ÇúP÷nh3*)f8©¨#¾†IA=2:Ôz¡"Ôc» þµJåU-í™ T䀔š4纊ßÉÉì)ÐÏèY×=«83UQŸcô¨c% ÐBví?ÌQqs3GûBß~ÝÇýìqV$‘cˆÈܨⱊ/öfü Þf3ߥ]É:>O]”\jLµéqôÎ3Žju"¡bHëÒ£Ó .G\œ~UBÕín™À,On´ ÉÙ-;nþ”ù@Uˆ¯hRð6â«Ëréx± m8íV¤b±³ @•ºÚÛýXnÝ“ž˜¤»µûNÏŸnÜöÍ%”ï:1|p{TÞJÒºÀ ªrM!]X½,K4e¡ªq骲y ªô«—h‹q`pECiu$ÓÈ· 8À÷ nÌuÕë”\u§[Ù¤²“¼¿ M³4oLg8æÿè‚i?»“ŠK•²×úÖÙœíÅ\–öæ;At¬ïí Œy¾Zù[±WåŸfhÿ»‘š¹z¥¿Ù¢Ù»w9Î1UeÒÕä,’Vê¸ÍX±î .øÎâ8¨®î¤†ê(Ónׯr=èk½”Mj ä(äùõ¨-ôÕŠQ#ÈdÛ÷F1WØáIöªZuÔ—>g™·åÆ0>´ ¥t%Öœ³ÊdI lzñœÔ°ØÅ³BrÁþñõª×7Ó}¡¡¶PJu8ÎqÖŸ¢ÒI\ ñõ¿¥ ñ¸ÄÒH ÊYÎÜUË«´[˜ƒlÎ9Æk4jW+²Y#_%ÏbòýÒDŠØwäûô£A'íaû=ºE»vÜóŒwÍC%–ûå¹ó1·.ßëQYê í$w+Æ ${uªÇSºmÒ¤kä©Ç"€rËD»Œ+¤rv¨,ôÕ·—Íy Ž:qŒR\êB;X¤ˆòíëLµ¿›íBÞí³t=1F€ÜnOaöÆCælÛŸáÎZ±s\ÂÑIÐ÷«2}JáæZ¢˜â’Frz½at.í÷ã Zœ[*Á£¬s+É)‘Wî®1RÞé«s(•Ç'sŒæ™¦ÞËu4©&Ü(ã’òþauökT ã©4h/vÅ›+4³B–fêÆš¶[oÍÏ™×øvûc­7N½7JË"…‘:ã½"]Èu6·;vnzP?vÈ–òÍ.‚劺ô`)¶–+låÙËÈ{‘Ò›xÐ2G #zö¦Ú^ÈÓ47+Žô»r[‹?:å&ó6íÇÎpsVXnR¾£–Ú„î]âEò“®EX’ü E•GÎÜ`ö4’%´µû0a¿vïlRÝÛ}¤(ß·o¶j´7“ Ö;…>0~½)f¼”ÎÑÀ ìê~”Õ‹ê6¨ƒVÞUÃË¿;³Æ:dæ‹K´FIeàL‚á互6ÆÕÎ1õ¦;­ÜZ‰˜0m¬;ѲÂ'qn 4Ë›—IDQ\úÒÚÜ4¬É Öiq¿a¸íôÅYhÁˆÆ8Å@Ó¸» m8§ÜÏä€e0Ñ‚/% îÝ“ž•–œ²¶Üõ¤†wó|¹@š×237–Õ¤XŸÈO+ËíëLŽÔ+Í»(ûHò7ãæÎ1ïLK‡ ¾`Z˜hK,Ûp;M:(„kÉ=M$òÔÇ'½=äRz‘𥯱)}߆)î»Ð®qšdc9N1D²•!Te ø×bÎi=ÒÏNÔØå%ЏÁß9ÎJ´P:4Ô‹iÉ9¤iqaÔÒ,¸h ºoÇ8Å:£iq :R‰>L÷ª›Xœõ¥eÜ1L7Ž =Û ‘@ Ï/ž¼Sùri»Û®8 }(UÁÍ!n;ÐçŠWž´¸Å7qíÒœE \R‘šE9¥'QŽh£<ÐFh‚h€ QFh Š( –’ŠZ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ JZ(¤ïKI@zÑÕ©h gÐGÊ)øP,1D<( ´‚£_õ†¥¤ÀÎqÍ6O¹@‹Ôâë@ã¥A¸ye{æ¤þ´g8¥ë@¬GÜ?ZNÍàõ#`…TõÐ+í>V}èc¿bŽ b¬öÅ US ,Gs÷Ö•6Ø‚¤`ù€?Z€±L¸0ª÷§pE¶PI±wghÍ)Œ‘@XŠ›|zæ««…‰Ðõ5t£`RМ•Ð)º7lšVa,é·¶*጑H¨«÷T bš°ŠYwSUÛ»cŒŠºÈ÷”­8âr™îáâ‰%‡fèbÛ˜©V4VʨéJÊa€#Þ˜Xe¿ú„úUsÿ!ÇúUÀŒ€)»~í£w¯za'ÿPÿǘ´«$# Ò"ªŒ {PÔÍÄI2? F6a±ÆìÖ‹Eœ²}Å;ÀÇ¥+ÊfHâf…S$€«ú¥ÿz¬¤H‡*€aJèŽ0ê÷ vЯ:–°Àê¤ò+ZGÎàÆµ€: `† û‚(o\P7 ¸RšvÓÔ*ƒùŠu‡üz¯Ôÿ:•]J°Æ…UEÚ è)ŽÚÜÏŸþBqýE^›ýLŸîŸåJcŒ¸bª[±Ç4âA (éêäúÕhÜ[M:Éœ• qÖµcD@v(P})ä º+ÜŠDòèTÒˆF]Šº§üz÷… BúHU벭Ȉë‡Pï4ª¡T*€è0¶¦™~Áäó¿~ Ðd1é%[‚¬ùù›ü´ß×8§²†R¬¨4¬%ž“ÿ‡ýãPj?ñÿoø:Ò5ÄjzñHñFî¬è¥‡BEåÒßî7Ò³4_ùoÿþµ©LŽ(âÏ–Š¹ëLÕ3%$zœÍ.pwcß<Š‚]ìnŽ:Öì°Å.<ÄVÇLŠrªª…PŽ€R±<‡?,Ë%•¼+“"“‘zše6—öï(ùB¯?AƒZËoɽb@þ Sä‰%]²"°÷X9‰5ÕÝÓÆ>R­Ç¥B“¢ió@ÙóÁçÒºãH—lhzLkhMíõ"‹#0®ax¬ídaÇ?©È©‹‹Íb'‡%ARONkmÑ]Jº†SÔL†¡ÊE\õÀëEƒÁ‚Af÷qËÅ sZl¶Îä`3qïW¥¶†f $HÄw"¤Ð ,…™‹¢ÇÔÿOëHî-5¶’\„99ö"µã‚(˜˜ãT'©­,°Å0XÕñÓ#¥GkZ2—¸šP>R1ùœÓ£ÿó~?ʵQ5 ŠG`1MÄ%ó/™ýìsE‡Ë¢35 b¿†b>N?CLŒ}«R‘ãÎÜ VâH»]CB)#Š8†#@£ØQ`åÔĆU†Þâ';`N’9n'óÇøV»ÛÂï½£RÞ¤T…ARÆ‹ Èw7pyyá@‚šàÜÞ4eˆUÈ…KcÆÏ½HÎ:Ó%ŠX® ±.àߥ"zÃpéo*ç•éíQ”d…'w3± £}ž@ü3ôö¨¼›‡E„¦Ns@¬Ë7-¿O-êýE²Çw÷A4ûˆÏØÌh ?:KXˆ´òÜœ‚(/©Ÿ±¤†IÙÎå"¤žåÞÒ!ž[!®) L«ÍM5“}–0œºg#×4fDŠÖ—¨‰ €~­ÿ,¿éK3Ot²Ì»BãñÅ?RŠI|¿-Kc9Çá@í£/Vfÿs}ó­:ϱ†HîegBýh)3u¨ ƒÓ4ÛiÞ¸9Ø _cœZšæ £».ïoÒ’ÚÉÙ&i¾VëAw)ùmöo´ïmûñÿש®§yÖÞ<à8±ÜçÒ›ö{¯/ìþ_Ë»vúõ=Õ“ªBÐÍ×4…gb8Ùß´;‹'Ë5\#]­Äîçr@«–ÖòÍvצÑéëÆ*mu›i½$ãpô ,ÂKÉœ‹¸î,T¶y úé¸k˜\ê æ*ÃéïöA̪KëíQÇoqs6ŠÊ4u*Ã9êj´ÐJÚ¼r„&1ŒµkÝCu©Dp¡ ?'ýªCiú¢B®Y\Õ½VÑî$ˆeÓ·¨¨-íî.o–âå6Á錑GQ4ù†ëß~¡þ•µYZͼ³´F(Ëàâµh)|LÄÑ?ãê§õ«:çüy§ýtÈÔzM¼ÐÜLÒFTÁ=ù©õxdšÕV$,ÁÁÀú:—¸S޲/ÞŒ~ßãÎi«’2\*ŒPŽ|ÍpPœNµcó!=:RHŽ“AœÓíã( 7Ð5¸Õÿ³øÒÎKJ©Ú…F%°qëK4m¼:Œ‘@ Œ˜äeÎG4Ð «9<Š’8Ùœ»Œf›²EÈ=èXØ´Y=i°}Óõ§¢íé°©Pr1LbOü5(éQÌ¥±št ãÿXÔ7Í&ÞÔ¨¤9$qC)¸s@¬Wpô¤ÇË»<木y'½&q@ÎS>Ô‰÷iq…Å09 czäÓ”äSpF@§¨À B'z:šb‚9 âŽÙ (Áé@æ”PE€ô;Ñ@Q@Q@ EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPIKI@ Iš(ï@8 Ò´)84Šk}áCö   °Ó÷†(±Í#"0'é±÷¤_õ†€Ì­ ÁºS2óB­8 —¶÷¥'ŸJˆÿ¯#ýÆúP¬dR3… óMƒî­6¼´BbBŒž”Å•Xàg>ôÛ¸>µ€q@6Nò*pzûR««.Aâ 7'<Ó²c¦?­¹?ž›±“õ§³RÇ ª¤³©ïš™¿ãןA@îHŒw”Ö•UÂäÒ[ÿ©ßñôŸ‡ó /¡aÜ"åŽ29ÒC}ê+ÌüžœÓdn#ÛÇN” ²y'HÛ$ûS„ŠSx?-UŒ–]ÜðzÔjOÙÜvȤ-­ÌlÛFGÖŸ$‚5ÜÙǵR”Du9©î¿ãØgÚ€¹:0u :gœ¾w•Îê-ÿÔ'Ò«Ÿùþ?Ò˜î[v¥@3MŠU•K.p9¢õþé¨lÔ7ûÇù ú’ê$}¤’G\•*°u § Öt4S–!{Õ›|–ôÝÅ!'rXgI‰ ž=i&¹Ž†$ŸAU´ï½'ÐScõäõ Wv/E*J›äSácÎáíUtÒwÈ;`Qü„Ÿêhö-Í:@s× Cqàì'#¨=jÏͨ nFGZH>]I‚ð9é@¹µ.=Ê$Â#ÇÚ,© nsTgÿœQKª“˜‡nhmË0]Å;mRCzN¸¹K}»óótÀª3*¦£Œ2½)Ú·ü²ü¥ÌìiTÝG4Œ‰»+×"§¬Í;þ>æúçLmê‹Ó̰G½óŒãŠtr,‘  Fyªº§üz÷…4’4Ž:ì¤Ôö¾ý¹l{TÓÜGsÁéŽõ’U³7`nó:÷éI!,ÖþîÑ×êh¹<ìÕ·»Šç! ;´Éu"¡,Hà8I‡—«°ˆcØ»QZªµ­Ù` 0OãEÙìm+«ÆNTŒ‚*+k¨îwy{¾\g"«éd›Ï@Ç•E¢ÿËøõ |Û®nc¶U2nà H¾Pœ.7dúV~µþª/÷:ô‘¤®;…ÍÍ«$MNÙä ð T·7qZæ“е: Óm˜¸–Éîy§œÉ¨Û‰yʧ_§øÑryÙ­muÒ“9Aê)ò4º[s»{tãŠÎ²5‰U8_˜`}i×ò‹ð¢ãæv5dqlíÑA'­ÔwHZ=ØŠ[¿øóŸþ¹·òª:ü{Iþÿô ¦õ±=Æ¥oo/–Å™‡]£8«QJ“F$·)èkÉVO¶@-å±ç±õ«º?g”¸ü¨L˜É¶\¶½ŠéÝ# •ë‘Iu} © !%;TdÖv‰ÿSý?­ ¢My„€0Éàý(¸s;#V ˜®"2Fß(ëž1UÆ©ldÙ¹±ýìqY0–Xïwoo÷‡ôÍ<¢d£àoóqžý(¸¹Ù»,« M#ghô¤‚t¸zgÇ5NBNŠ ë°:]8‘¦±^£v(.ú’ɨA… bGÀ©šxÒ4°ØzZǶDk;–` `úR;7Ø¡;w7ôÿëÑryÙ«ä3¾Õ$7`GZ|÷ n¾yéY× #»·òÀ*ž>µ>«÷búšÌìËàä;óQGp’JÑ®w.sš’?õkôFÓþBÿÀ¿2›Ø¹,«nlãÚ–7 uè}j ÿøö?QI#Nã®Ó@¯¨óym¹?\qS3…Bý@â³QWìNÄ ÛúÕ¤$éüÿtÒÉ¢•eRËœgÒI2ÆÀ6r}*+õ-þ÷ôÛÏõ©ô¦ÒåÊŽ9VBBçZ’ªYýç }KH±€[<úR†Cv#5 ßÜ_­+çìƒÝÇ „-ŒŸ­9ÝP|ÕTöu=óN<ÉïA@®XIúRsPŽ'lqÖ„Êrzñ@\³‘Œö¤G8¦Eþ§ó¤ƒîŸ­$g Œ÷¥¨§þ”t b;PÌ­2?õAæ^h"°n”›†ìw¦'ß4¿òÖ€x‘C}ÓMO»@Å,¥Ï¦/CGðÐ!àƒA8¦žÔ£ïP1zÑži÷¨h ô t 4QÚŠ(¢ŠZ(¤ ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤¥¤ ŒsE&hHÍb‚iç€2sJFE7qíN#4psHS'9Å*’sšBÇ8r¢š NiU· Eb\ŽÔ 7sÐÒªúÓ]ˆ;W­*9$ƒÖL¾ìÓˆÈ#Ö˜\ù»{SØáIö cQv g4òqŠX˜²’}i²¹R CÙC. F°€Ù'8§Èû=ê1+Ç€$!ÎAÁ¥H•T޹ëI3”PG­=NQIî(/³ŒýãJ•×réQ¬Œg)Ú‰¥*B¨ù øÓbÎi¯éU÷cãØ¥%ŠIÁžC–P6Šè±$bEÁü G¸FÜ[q({ŒD¬'µ69œH@9 Z’Ø;n ´ž¼S–êZ‰çr챎­9n3 r>aÆ( [E 1`;b¥š?56çõ\\È¥YÀØÔù§a Ž ôƒBh×dasœw¨Ì¸ów~ö¤·œÈJ¸Ã C3ý¯ËãoÿZ˜ô'‘wÆËœdc4È"òP®íÙ9éN•ŠÄÌ:šŽÖF–2ÍŒƒŠ©–JÎY\¨=F*Äq¬hz ¨×R³1ˆ ‹V`—Έ60z@•¯ Ëk ±ß»>ؤžÑe}኱ëÇZK9ÞbûñÇ §^JÐÆ¥1’qÍ ÒÃà`M«É=M1-¶\´»óœñŠ{K²ßÌn~P¦/'\HÊ dâ€m"ÍͲσ¬;Ñmj°rYz[‰JZ™öQm){a$‡×4ÃK’×}ÊͿǧÜ@·ínäÚ©ÙÛtˆ£ËSŽ•ufó-L«ÁÚOÐÒÓ"·²XdÞÎ]‡N1ŠuݯÚv|ûvç¶i,gyÑËã ö·“4®°(Úƒ$ý(–4j­µ§‘3É¿vîØÅ:Òãín# 8"¢³¹’k‰ȃŒzcºÐšê´E³vÞsœf!-ÄDî`ñÖªÝ]Ê.àîM-µöøäó†1“Žô‚êã?²ÓúÖÙŸ»ëV.lãž5_¸S…#µRû}Î<Ý‹ånÆ*ô³ÿ¡™£þîFhåkb¶î\±w=ȨeÒÑä,’ªã5=Œï=¹yÈb8ªo¨\;HÐ(òãë‘Ú>[QB±B"N TVdßûÍû±ÛÅFúˆK*¨ÞÇnßCQC:O\¨Û cé@ï¢Õí§ÚÑW~ͧ=3R˜U­ü—ù—nÓTn/gk–†ÙAÙœŸ\u§Á¨†´’IßP;ç¥xÜbi$¥f@~î1V/,Rè«n(ëÀ vª#Q¹M’ÈŠasÆ_½¢³2ÄFxÁ#Ö¹lIJ±KMÄ1wn¬E$–[ï–çÌÆÜ|»­:ÒàÉb³ÊFpI#ØšÎ:•Ó™D*pF(qI'› ÇœoR¹ôÍAciö8™7ïÜsœb«Ýja-"’ 7ÉÐØëMµ¾œ]‹{µ›¡éŠš7s¤¤Ó4‰!wÞÍ\¶·KhDqô’{šÌ›R¸’iEª¯—$’3;ÔãTÙær£ÌnÞÙ£A'’XØ}’YÍß¼tÛŒ~´^iÉs(•\Ç'rsT¢Ôîc’3r«åIÈ8ǵ{S¸’ÚÝ^"7‘žÆ8´:ÖÆ+x^?¿¿†'½V:É•ŠgîãúÕûWim¢vûÌ š¨—RQ­ÉXöç¥j:§„KnЃ´ÇJKK³CåîÝÎsŒT÷$Qdo^ÔÛKÙv‚äã<ÐW 4´i $…õ\U‡´í„<…^‡¾j‹j]âU!ç"¯Ã?kæ¨ÁÁÈô4å{Ûéë ÙˑӌT·vßi 7íÛíšO¸’á\ÈGÆG5Ü­;Gn „ê}qÖ€ÒÅõTAŠ‚+o*áåßÙã2sQÅzÙ¤`7/ý*¼v¼Š<¶é@î‹·yÑìÝ·œç¥Š?.;€éÖ«Ü\¸‘b„ǽ-½Ñmë(à Íuq ŠîáÈ_LU–ŒŒcŒU/µÌA(Ø*in¶Ä…Ìþ½¨Ñ,y(Wvìœô¤š5”îÆ=ª8g7Ë”i­s#3y`mZêÅʆ|¢ÇvsíN†O6=ÝCQÛÊÒ3ÇÇ¡$ÑùªqƒéN <°‡‘ŒT2LþfÈÇ"–9ó¯ë@]-†ycJ’HƒØŠ‡ÏaˆI©$”¡9-@´A9ÎM4À3ÁÀô¢9Ib¯Áß5ÎJ´P= ‚€»GJHÓ`#9¦´¸ŒÔÒ,Œhî›ñÎ1N¨šF,BŽ”ômÃÞ€M¬NzÐÈ硤F%È=(f;¶¯Zr¨Z6üû³HœƒÖÇ~;P1Ädb…ŒØéÖ1Î )^ip1Šnâzt¥ÝÆh ŠR3H Ï4Î(£Ð™4¦ŠJJ1E¢€ (¢€ŠJ(h¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š))h ¤íN¤ $ÿ,ÊǧcjîÎiH`€G½bª2v+Ó˜®'CÔÕÅ”=¨(„ä¨'é@¬St"osJ[Í6öÅ\ ƒÈ¤UUû ¥bš°ŠYwSUÛ»cŒŠ¼Ê÷€?ZPŠAÊg»‡Ž$\îSß÷7JÍÓÿ­VÕ6UTaJʬ>`÷ ,Tµ§wwšü„éWPö¦ìMû°7z÷¦õþé¨ly‡ûGù ²@ ‚2 "*¨Âµ¶¦j0‰fGq«V*VOñŠ’69eR}Å:%bŽ÷¤ú ~£þ©Þ«(‘¦v*\PêŽ0àïH-¥ˆ'RöBƒTžPÖ±Ä3¸1­`”ÁaòC}9 nAp¥4í§¨ æ)-T¾žTu!…ZuVR½Á¡Up€íL-©²„µ–&;WmЦžsÔ©5a¢‰Ÿ,ˆ[ÔŽiä=Z@£bŽ—þ®O­VÅ´Ó¬€ä©µcD@|µP\RINA‘žÙ —B¦–„Dìz1â£Ó¿ãîo¡þu¤` bG1(ªõÅåØÎ”‹}SÌ“;O9úŒTPFÓý©ÐpTãóÏô­y7‘U‡¸¥EUP¾‚‹ —S Ì¿aòyß¿?…h2ô’­Ô'5gɇÌݱ7õÎiîªÊCTõ‹‰KL¬Xz±¥gÃ(‚+˜¤;ÇqšÜ€ÚšðÂîãBÞ¤ Ñ`qѯ:7#äþð§JâîæÝb!@?Ö·`€AíLŽ(“"žåE!’’ =NV”ãß<Іìn21¹,QIƒ*#c¦áOU ¡T@(°rô“,–P@ —Rr1êkJý zHCÕBƒúUµ†“rÇPiÒ":^àô¢ÃQÐ¥h†Mbõe`?3Yi:¦Ÿ4 ö`GçÒº(ÑQ  £ *6‚“sG~¹ f‹ Äù‚H¬í]‡çÛ'"¥Þ/uˆÞv‚ 'Ú¶ÙUÔ«¨e=AØ¢Š0|¤E®ÑEƒÀ‚Ae%Ôrƒ¸¡Qõ¤ò%¤Çf c5½,0HÀËl{¥À ·1E…ìÎnyEÒZC%Õvž;Ö–¶1eôqü]Ž#rÑG·r f,qȸ•U”üÔXj2;øòƒýÁT#ÿó~?ʵUUT*€¦¢¾g¯z kc7R+øf#äý 2!ö½JG;pyü1[ˆêC¨eô"’4Ž5Äjª§û¢‹ —SD6÷¸!Û Ð±BšyÜ1»$U—†pÏõ f¤ ƒÒ‹Œý#îËõ8¶½›Ìqøò+J8ãLùj«ž¸¢Hã|yЧ2(] ¨¢f³•Àã þ_þºWIo J e'5®‚˜±Ä­•D ì(°r”$g¼F»ÏáŠ"C4“²ƒ‚?ÑuFp÷¡UUp íE‡Êf,€Z´g;‹fŸ,l‘BÄqëš¼cŒ¾â«»×öŒ0{Ð.Rˆ"kÐÉœpi±·”%FêF*ú*(ùJFDc–U'ÜP;Y©{ž)–yêÕ"ª®v€>”Çb®|«¦-ÐÓcBÑÈE\eVûÀ­( @¬S. *Á§8(ñ“Ó¬„@Ù 3J@#÷ ,VQæLÄtæ‘X,l§©«J({RRr@ͱ]”ˆ”Ó‰ß"â§<Ži €±;³O„pO­<€zK@XŽ?õC|²äô©ðh ´|±=©å­BœúÓf°ÅÐYتqÞ¢ ÆQê3Sʛר¨B³•¢ñ@˜02Í´œH’G)Ò+$›×œÐ»«R-¤F$ÉÉ5<‡u¹>¢¢Ù!< ššEÄGa@! 8ƒ>™ªáK£ÈO"¬Â¿¹Á÷ªå$MÑ€jƒÊÆäõ èÈ8ÍHð%@å…64yeV~‹@†g•òH*[7,Œ§½)ŽŒPŠšÚ#ÝM[ÛÇÔŸó©o?Ô­Gn¤\9#ŽIt B@ëš ëõ ôªçþB?ô«0!@zâ«”o·îÇýj`úë’ë8“LŒ.ü°ISRÝÂÏµÓªÓ äŸÎŠB{‰{ÿýó«ÕJí§ŒÀÿ»LkvPÓ¾ôŸAOÔÕ/ûÔ–ÊϸcN¿Rñ(Qži 쎕ÌvA—®ÐP(Rç w3Ñh¼ÛAC´~uGÊÂÀ@NzÐ)žCq,1ç @Î=M;[Ï,`å@'J’æÝ‘£’.v9ö¢ÚÝä‘å—ÀŒzÎå]†H$˜îR?½ †[fä… š¨až0Ðr9ÏZ¼ùVf>§iÏÖ„D_ú¹>µ[i¼šff#j’ô«zj2Fû†9ªòÃ5¼Òy`?¢·2 \œ†  ?þª‘­– ‘Žç«Kbßbd8ó ÝÿÖ¨î q8cã9è(™kS;¬Ôú°4©!‹K:„â—QBÖ¡TtaNŠúzÄܸúPWS/Ë?fûNöß¿ýzÑ’C.–\õ)ÍQò.vý—jãvìæ´f‡fžÑ/$.>´"b·"ÒÎÛ&>ŒMgª5ÒÜNìw ´´ØÊÚ•qŒ±ª/ű’’^3ž¢€kD]ÈÚr.ã’ÅIî@ÿõÓv›˜XÊ æ*Ìš{}P`ʧqÿ Š('º¸ŒÊH€ŸJB³”ßê#1 ¹ÛjŸF™6$„ÁÕÌ3ÚݼЀCç¯lÕ2Õ­ãf“‡|qè)'ÌU²ÿÄÿVþt_–¸Ôc¶,BqÒŸg®«3‘…%°sïK¨[Ê·+uŒdjÞé^Òg³žæ w* QUÄM-¬·lì]\ŸÖ¯YY¼¯4×` ïÞª›{¸Õ­©W`s‘Í"ZvîîI¬­Ó$qõÁÅ:%6¢DŽYç¾jk­5Åœ"3—ˆóŒçšm¬Ý^‹™À=;‘@ìî&½÷àúéVõ‰Ú> >> endobj 281 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 701.8656 342.3127 711.4339] /Subtype /Link /A << /S /GoTo /D (subsection.3.5) >> >> endobj 282 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 675.2861 412.4363 686.9756] /Subtype /Link /A << /S /GoTo /D (section.4) >> >> endobj 283 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 661.7369 324.0703 673.4264] /Subtype /Link /A << /S /GoTo /D (subsection.4.1) >> >> endobj 284 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 648.1877 346.0097 659.8772] /Subtype /Link /A << /S /GoTo /D (subsection.4.2) >> >> endobj 285 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 634.6385 482.8863 646.328] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 286 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 621.0893 181.9186 632.7788] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 287 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 607.5401 465.9771 619.2296] /Subtype /Link /A << /S /GoTo /D (subsection.4.4) >> >> endobj 288 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 593.9909 384.5551 605.6804] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 289 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 580.4417 482.8863 592.1312] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 290 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [99.3502 569.0137 174.0095 578.4608] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 291 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [115.7139 553.3433 420.0097 565.0328] /Subtype /Link /A << /S /GoTo /D (subsection.4.7) >> >> endobj 279 0 obj << /D [277 0 R /XYZ 100.3464 764.2205 null] >> endobj 276 0 obj << /Font << /F18 200 0 R /F15 235 0 R /F45 230 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 298 0 obj << /Length 2884 /Filter /FlateDecode >> stream xÚ•YKsÛH¾ûWè¶tUD³|í-‰“-OÍÚ³±S{˜-R2+©T<ö¯¼š¤dJ“-WYý@7hàT‹þÔB)ã›$ZÄ‘õµÂÅj{,60÷¯ %4KG´œR}x¸¸ú¬’… ü4HÕâa½0iäÇ6¶°[âë$4‹‡üwO].UÞÍí׻믗Êûøpsw{ùÇÃ/Ÿ.6µ~ªÓðüQª·gÑ@`}c#gS‘o•RÃQ¥îÛæri”—ïW} Gjj<N KúihZþðT\.u¬½ÛûknÔ°4ÛÒ¨ñ:øU^ C?.uâIèEÇT«f‹;\Ù9Ï÷ ÿ6ýŒ+•w}{ÏS]Ñm«¼r»«Š-Ô8×g=,/›º¶µl‹‡Ê‹eD¡@7¡MY(b/ëøü]Çý;ŽgËc(3Dmv0…Ù#²®Êç_.ëù—K *f­ÁêM“UØ‚s æ ç{Ý9 q2Çýþ(3ðA•·¢³É&$$lÒ;>YÍÚVÞóDa84'>*Ô¶4ÆzNûØæ«%F^Q3Q»'k¥vã~÷-7`þÊß9eN|²D¡6ÞN‡p籞;Íš¿ïG€[pKVÙ®'VÎf¬I½u‹²á*±Sbºw†'xÁ&?rw@=ÿÌ-M>‰á˜EK‡3Iâ æín‚XLÚŒ÷ÙòÈ×ë߸Av¿ÿÔ·ã.oà‰xJöFYw‡{È5Ù> @úÁÅU6 œ¯MÞÆäíh`q4"H{bÚ;2MÀd†W¦ãkáB>Äì£/R28ÐÆ«¦ÍÑñ»ñ>£—7BDLdÙ á= ¿; €¦£Úb¸Bp4f ÀCs€ç,Q`éñR§Þ‹ )Ì= à9Y°‚*™†¶…‹c#¶À"Ë<䉷}­ù™#E¥ŠC"’8î>bF=lԘȋËÖ$ï–;N]Ø~ãĤ ž±«BX@|`ùÊUVU/g\é‘£(¬R–ú©º¦f’®YSÜ%ñ2 ¿Ø&ºx7 ¼à{MÏŒ!™`:SrlĦé$¦*´–ãmƪ gL¦ÃÈÛfýÞ©)Œ‡¸†S]Ÿ=Vã§?aø6Õ¡°©Î;Î…@¡¼ÃéðO;ŽÖ ïÌ¢ÑÑ¡7œ‘O‘ N¢;äU¡½‡œm™tŠÝÀ)4ë♬ڎ!ð|ÆöÓÛÑìC3z,dof†â!¡™z|ˆ7{ç|.å­›v[ä­IÎh ÷+žù¼ÉçÛ ]æÛéT„²@#ƼM€"5† h£ßa–ÃàKS`{È¡<(x)ë OŽ‘PV’™0´c}Ëçžp<柊3zû+ y¿^scLÎB‡î0:b`„˜‰Á·é™è•¥Ú¡oä²$îeŒD] ª#B—‡»}pßl²*f“`¶ÜTbÈ~Î:Žniô'Ù$«3tà—WN6Ñî éî(àDvp®ž9r”,Ú5½Uäèµ!7š á…_Ë,Dšfæ” ïÐZïÛ ZOš3±w³ÆW¡E(=Gʃ ;eÙÌžÌ÷ñQ#*y¬šÉ›ªF G&Ã1F0"*J5€t/¤mAÊà°¼¼e8œVÍn,*ä¼ìöL‘B®Ãj¯ÒeWƒqÍOxø½ÛcŒÜsgÈûÊl´>LTqÄ•Ýôöô²)W•ÌJISØ’R¢Çª™žWMÏÇfÚ7wùî—óÑrSpqT›EŒÕPªjå'*Ñ ã§a’Hyu¦†šÀ|œ.–:¶ÿrlIÜHS¹¼ÑŸä}ÿ…œV0=šf ɘÌÓüžË*m‰!`òÒÄÉ¿+ȶ3‚ëfÆÐõþ„Ãѽ›ÀãH=k€0åg±¤Á´q?+ L&5#ÖÜK ˜ø f©¼k³tIM ˆÇÏbŠ…¸k.5Ó7/½†ÆI&šE> I}ãknr˜½l øE>- Õ”Ül\-€æ´lÑ µrTæé7ÀûœPJâdÆ~¬ôèæK æy˜!8Ê0V NÃ*vc¥Êa2KÈäà_¹Ò5O¹MŸËoxžåX““<ëÔœTqu»é–gü¾ìf Fƒ‡T #•zh†¬­Ë”8³7V¬À9LÐ’£XÃB|+çœQ¾1jêŒzέmœqrbW»æÇ#k=§ 2ËòÆM¡9?ŽeÖ–Ö¡DƪkÝHáGls4+çR•å„¶ëÉL ֹƿüH>}ùò¦8u&ȼçôo7GPÙsßñxN__Æ‚ßvº˜âúæógbûéöã'hÜóð¤êÜæ¯EÍ,#¶ßú°Òr$¶—JhDûÎg m•ÕîŽt¥o35##fdÌAYµÊmLþ y±°p²)Nû.Åé£-À÷ècÐ~*Z÷ò<ýÀ€Ùãú}ä$*„‹<ýå9}^ÍHïLiú ¦Ö¡bþ>tS±ÑÅ‘îòÑ`Gq§ä´œåñÿñEŒ#ö”ÊaÍV’'È—ÝäBÅAÆWJSOü£ï¦îC§ÒÚ7q¢æ>› í‡i`pîûÅï‹h~¹ÐH“pñ ÀW)(c{¡BíG*Tn¤º¸¿øÏÌ·`¥­ŸF‰¿¿Ú~+#úü ®ŸhÃñ?Ta:ML„YAY†$dˆ”LDÏÚ¾ßýóêê™PïÙç»öHšÐE}ŒÉWm!%Þv…+ž®š¡P¹Û\íÚMµé®Ü·#¼ J‰7W+t´ô*¯;ÁÒéÑ—r¢ØW6M§Xúóç&Fßè¿?â8tVÍöêž¿±ìªâ#¿Oôû–K3³W¾=µÒ}mTzþÓ}¤|­sâ˽#sT(=ù…~²—cø*€ñ–endstream endobj 297 0 obj << /Type /Page /Contents 298 0 R /Resources 296 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 300 0 R 301 0 R 302 0 R 306 0 R 307 0 R ] >> endobj 300 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [417.6558 308.6947 495.9258 320.3842] /Subtype/Link/A<> >> endobj 301 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [112.3897 295.1455 136.2005 308.3544] /Subtype/Link/A<> >> endobj 302 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [134.2079 295.1455 140.9328 308.3544] /Subtype /Link /A << /S /GoTo /D (Hfootnote.3) >> >> endobj 306 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [252.7696 234.969 334.7133 248.1779] /Subtype/Link/A<> >> endobj 307 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [332.7208 234.969 339.4456 248.1779] /Subtype /Link /A << /S /GoTo /D (Hfootnote.4) >> >> endobj 299 0 obj << /D [297 0 R /XYZ 113.386 764.2205 null] >> endobj 6 0 obj << /D [297 0 R /XYZ 113.386 727.37 null] >> endobj 308 0 obj << /D [297 0 R /XYZ 129.9737 125.6658 null] >> endobj 309 0 obj << /D [297 0 R /XYZ 129.9737 114.7069 null] >> endobj 296 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F23 305 0 R /F24 214 0 R /F36 207 0 R >> /ProcSet [ /PDF /Text ] >> endobj 312 0 obj << /Length 1955 /Filter /FlateDecode >> stream xÚÍËnã6ðž¯ð¥€ T,ߢzë6Ù"E‘>b ‡¶ÙVb¡¶•HJ³Ù¯ï<(YÎÊñØC r†óæpFj&áOÍ””ÂXog™·Bkéf«Ý…œÝò‡ ‰Ò „•:ŸY!½ H2{œI‘y"ØÅo®wzvY_üz1ûõÀP‘[ãfiæƒÐÁ$}·¸øæ½  “Èe®f‹»Y®E0Rv¹PÆe³ÅúDÏSP[&¿]ÝþòóÍíÕ<5Æ$—×ïa?yõÛÕ ßÏUr…À-ãßázñ;m!…1–ö®o.y‘ #4Ó~Ç{&¹a*‰4FH+9ÿkñãÅÕb0È‚‡Bþ¶#M:&"“5 -FA£É‡ˆ(/¬Rj°Y¡ÍeûªÈ¤Þ·åaçžO\ƒ&ȤÛÀ¹ªÅ…JZRpÕUõ[2²A»Töë ì­#vlÐÄ¢ách,ð#²(bIÇ ×ÍuÇÀ¿’=Ç2Ù1”°Â´šOÈo͘›ÛH2Ï$,]%ÁIF8›k2ùaЪºé<éD–ÊØ«Œábûò1¨DÌSkòä÷y°d5‘:ÙñNµgV·½¬Þ›°§…ñŽ2oKòϘJ3ð\û šÐ<À ØÜßOY:„ÍyÈO€)EÑÇ æ'#ڮ誶«V-¯ïê‹qÉ8.5n¸è£¶‹«¦Xq*€Cœ’Ébsˆ6Qb öÖavÔqO ÃÀà†!ž=Ú7­ƒŠÀ·o0 vˆMÑ•÷uS ^cTL ‚iÿ¬¶é[®¹æPáwW7½ŒžMG”[Á· 놹sT7@G õÙIÃCM% a½{(°F-™çáÝño3.*¨ª÷˜MŠÜpÓÃ@Ññ‘ǧ²©€v⺃"Ú o¢³¾¯w|kñfT,¬;s ±öÞÆ"<º^èÃ>fXÓ¯ñ@_¬G7èîÐì†1o¡÷Á Ì«Ž”JœId‰ScK´9:'Tد}¼çŽJ-ýƒÁ|ÀU±ú»ì0;s’¯bqžvÓ8§Öia^W1‹-kø'DÒP80¢Ö 뜗>ƒ¹O<ùWSyºOWÛ¹Ö˪³#?©Èѹ -ƒ yä¨3!³IŽË´­‹®Û3ëuóN›DI• ºÁY­Nèö4çZ(¿‹.&{o0F²ç›[`\@m«Ú¾bª¢ñfÖ\©|îúbäʬ7mrï{Þ >wMº¯éYêë«’úë£mH̹­Ó¨7mUïÙ!Ö2OÔ9ýó` iúFÞEGìðU•ýX›é2º/¬§›7•|‹U%Ë]ã@æ •] 7xZ›§Š>%Ñð“´B­þ&Ë»šn  -v±0Xº1£=W…b[},°}Bý”– ܼù¢J íBÁmÊ3*ê à&*ÙU¼>ƒEψĦ)£Cµº\yõcù0eA5tìÜÁÇ~«\ƒ¨‘hm­WžôHÈ3+ñíÕÀ’´y/¾éš’‹rB²áê#^z­tìp4\ª¡K;Ϊxn·ÌC.Ìͳy!šGF´ŒÀÊÁšpDP„›âX^Ñ1÷ŠGFlè1d'À˜ï^U—É~$MÚMM-Õûck Š@Ù÷¬ˆ?š @èó¦ìÏöòiqv¦b²ŠK:@ãòËü 1ûª}¥×áØ~rN*F¢pDÚðýG>:øW7Q7tä:|–ÒÈdÔà\b“²YÆâ>")@ê i rR•¨&Ãs‚~@ú%%è›Ef?Ëé™X2Ín̆ªñÌè¼I¾ãæ™Ü3ÕÓŸ‹ž,>™‰‹Ð0Á<]±1^Œ¿¯øEiÏÍPÝ­0泦}•|ÅÃôRľPu›ÑˆužM ³Ã­ôúqÏ•9YåØOcõD°Lüý¤8â©ã”F²Ñã‘î'XDVûÕ½´.ãùîñüÈ„³âOšC)È\,.Y”„Àè©•’ÌÐÏUSRò.–É<Æš>k0Ñ›áÎbœ€nÔòÁj:M]¼žƒÙÂ\Í÷ IÖS9Xt¯žÇe;œYÇé6PtÅr[¾=Û8ë/6Ó×·Ÿ^üty˜Àû×ü:ˆÇëww4†C7 é= é÷üacü]uøê•Ð:˜É«Q:¢šø˜ S™°Æ˜¡W܉O¹ÿ‰Wtendstream endobj 311 0 obj << /Type /Page /Contents 312 0 R /Resources 310 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 314 0 R 315 0 R 316 0 R 317 0 R 321 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R ] >> endobj 314 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [313.5309 652.4149 329.4629 664.1044] /Subtype /Link /A << /S /GoTo /D (subsection.2.1) >> >> endobj 315 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [389.9546 652.4149 405.8866 664.1044] /Subtype /Link /A << /S /GoTo /D (subsection.2.2) >> >> endobj 316 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [389.2699 640.9869 405.2018 650.5552] /Subtype /Link /A << /S /GoTo /D (subsection.2.3) >> >> endobj 317 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [466.9543 640.9869 482.8863 650.5552] /Subtype /Link /A << /S /GoTo /D (subsection.2.4) >> >> endobj 321 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.7189 524.9358 212.1357 540.4775] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 322 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [176.8401 511.3866 201.2569 526.9283] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 323 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [166.5674 497.8375 190.9842 513.3792] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 324 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [172.8704 484.2883 197.2872 499.83] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 325 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.3553 470.7391 209.7721 486.2808] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 326 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.0826 457.1899 226.4994 472.7316] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 327 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.234 443.6407 191.6508 459.1824] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 328 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.2644 430.0915 224.6812 445.6333] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.6) >> >> endobj 329 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 416.5424 192.1357 432.0841] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 330 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [166.5067 402.9932 190.9235 418.5349] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.3) >> >> endobj 331 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [184.7189 389.444 209.1357 404.9857] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 332 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [229.3553 375.8948 253.7721 391.4365] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.6) >> >> endobj 333 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [205.3856 362.3456 235.2569 377.8874] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 334 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [196.8401 348.7965 221.2569 364.3382] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 335 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [173.2643 335.2473 197.6811 350.789] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 313 0 obj << /D [311 0 R /XYZ 100.3464 764.2205 null] >> endobj 10 0 obj << /D [311 0 R /XYZ 100.3464 727.37 null] >> endobj 14 0 obj << /D [311 0 R /XYZ 100.3464 598.8065 null] >> endobj 18 0 obj << /D [311 0 R /XYZ 100.3464 145.9313 null] >> endobj 310 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 338 0 obj << /Length 2011 /Filter /FlateDecode >> stream xÚµÉnÛFôž¯Ð¥À¨ØY8$'·ÄK‘Ü"6ÐC’MÒ2ITHªŽûõ}Ë EZ”- ˜ofÞ¼}©…„?µPÊD&KiGZK»(¶oäb g¿¾QgVc¬÷wo~¹VÙBÉÈI§w e]ät–µ,Ò™5‹»ò“ÐË•’RŠW·ü~s{µ\cÄå‡kØ×W¯n¸X*q…À-Ÿ¿ÇõÝŸ´…ÆÄ´÷áæ’.2‘fÜw¼gÄ PÂã˜HF°’Ë/w¿½¹º4Š] ‚:ûºÚÖ©ÞVMô6Id¤T‹T¥Q–Ù„ô.ëÏR™ª]Z%ª]A/3i"ö¸Ê‹¯UwðÏÙLü²ò-¬kÇ\$8ÂD6všÉ¯€¾ûºƒÿÍR§â ¡ÒköËl |2QVlŒÏÒJÀÐQ) ¨*5Zh#,]"tÅñOÈý%»ûÕ=\ÎËoÈõ-ÏÄOr䪈§%°õ8ä—µ‰RÏYÚL •©ÔsVYäÔ,çݪش%jy_÷GzH 6•§—¨4*v6г‘M^ÐS^“®Éû~3%e=T)+”Ò2ÐQQbÏÈ…¦Ø³ÑýÈÐheÔ8P•&Î D%ÄË,ÑrÞÌ6_w§Ž”ž±6YŒÖ´À ‹2u†þ#Z’ÜÔ£Ãò-‚ÕØñà$›9#¬Qž*˜TŸ¡JQØ×ÏcB°"zZ™TR¸Ì“R‘Ôg¼ÃV£>aTç¨Ù­‚)È&§\Œg»T‰4°‘çì@AU”hì—A5øLk'3PJ’3ºÿEáÞvu³›š1”¬wé’6gRŒ¬¸Þ*RwȧoªöyJ]ò1”qÔXfóÔ3ZU¹ëä‘T| })y¤£ft·Ì ¸:÷ù³CåÑe[ôÖ=žqê7ä+ªáĨ`AáGj¾Å‚d²T¸DQÄ`FËù<¹9l‘ñ9~" ,Êô•ÜÓûäé}¬Ë|ës6ü~Lˆ|ÑnóMýwÞƒkßRqÐÂA*»ÿT$Âý·˜–Ìx/-€^Än’ª!Ö}žð°ü¶ ÆLÀ–V“̉ûƒ~ÜÏiP¡Ê§bEª¤H D'RrWÓÐ\Uä¬ÕØÕVZCá¡ÝBU2ãÞ yˆÁSÃõÒ€Îy Y Pæ;£6PRG—?€ib‰¦ÁìîpÖ#eŠž’OC“ÂÃj¤=š¸¥ZŽX9#ÌZ§e´ ~K4>5o"-¿òÍOï©O@¿…­ò)§&›•m×qkÓÌ›új9q·8çd‰ tÈX\¥4yÏGä "±küÖà\D®·¬2IŸs„„ãê;Fí&'ÓaÉDòŽ¿%çn½Þ~ àcS¼-W ht÷ÈKÏô!ËWszõ‡!Œ;¶iÑàö¦äA 4X71fî/Ý#þÚÛ¿¦C¥ eû´ÇxRMË—Qí¶éy„*š ïžÄx÷3(çs¸¨ö=#Rìåâzf¨lf›Qã[ЦÊKŸÖ kм¾jýL¡yžÚÔ$¾o û–Æ£ME¾ì¢c¢M’2L»xÈ0Ÿ|ša?\R²ƒ‡b2%)N”øáX !1'ێח¿ó—‡3ðîŽÁàC²Üiv†¯%p6Šk˜˜Š,-WK¶/U>ÇÀ÷ØÌÝ €ós)S‚c¶´Ó‰«чGO5°#¶ Â%€Îëq¢Ä{ÿDq6û: ܘÀL°P(‚í}ùoBß cEèFªÌz[%‘3 <]t[bñn—ož;¤ß½sƒWÅ ÙPFãT|¼F^È Ä~¨ù‚GGs Œò#z÷¨øÂ—§C†»ý±·8ÄUÉ7(÷xÅcTQR(!Aº‘AW©Š´…&0±kõû&Õ1¬Bq*™’ïR(/5اZž¸QúÂæ`\ *L*Ã7Þ¬ÇGo3:eè `’Þ—õš¶ÕÊ®03Ñ’oHæ°¦ÈD¹j 10jsØ”¼ÙVUË»æjGúEÈ?3BÓž"žsF|C¾†'·:—²FOr°K_4Œ¢Žœg5Å Þ!¯F–a™a»FÔ’][‡SžÌ´„¼š˜óC”›–uî†0¸Ød”u.W¨äÍ-ßl™CC¯Þâ˜âzÍ;÷£Ïoøš 09XÊÍ÷à\4Û}½©|oðm¡ulýcŸ2jÜ«qö>PIÛ­G÷çêÜõ¸çqôuÁ»õ¿h+z¦­,µ'Ý%ñ?Üœé0>º’lrµÞñÝÖ¿ ~¨ÉÄ–Ø«8Õ÷D\øsŽQBO+0¶ãpÑWjýk­®ü‘ïpëuN¤LŽÆ@ ÚG5l&J..Cßè§£Ãð28 ûµŠ¡B­'M×yÇ9×ö¾h¬4ŸêQ™]RE+¯ŠöÓö!D«ß<ޝpœ7Ô™!äõPOÎ\+ÛzõJŸèá•÷—Ïȱ‹Ñ;Zâ‹GŠäD’îq˜Mi?HˆÈ…ÿEg †Wýã Ç@†«¾ÞÐ`ÜäTþaÓ†!¢¹y?üjz2’L'‹“`ì^ÌMx1?Píóï%1} ê?»†ß‘°¿ÎÌë¿5æ~j~A µLÎþÌ;ÃðÈhHendstream endobj 337 0 obj << /Type /Page /Contents 338 0 R /Resources 336 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 215 0 R /Annots [ 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R 348 0 R 349 0 R 350 0 R 351 0 R 352 0 R 354 0 R 356 0 R ] >> endobj 340 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [232.8797 699.2754 262.751 714.8171] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 341 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [250.8797 685.7262 275.2965 701.2679] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 342 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.8796 672.177 214.2964 687.7187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.1) >> >> endobj 343 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [179.6069 658.6278 204.0237 674.1695] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 344 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.9099 645.0786 210.3267 660.6203] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 345 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [218.4251 631.5295 248.2965 647.0712] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 346 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [198.3948 617.9803 222.8116 633.522] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 347 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.7584 604.4311 205.1752 619.9728] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 348 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [208.4554 590.8819 238.3267 606.4236] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.13) >> >> endobj 349 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.2736 577.3327 213.6904 592.8744] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 350 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [186.3039 563.7835 210.7207 579.3253] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 351 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [224.4857 550.2344 254.3571 565.7761] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.14) >> >> endobj 352 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.6372 536.6852 218.5692 552.2269] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 354 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [246.1056 285.353 253.5527 294.3758] /Subtype /Link /A << /S /GoTo /D (cite.rfc4035) >> >> endobj 356 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [234.7286 129.8501 242.1757 138.8729] /Subtype /Link /A << /S /GoTo /D (cite.rfc4035) >> >> endobj 339 0 obj << /D [337 0 R /XYZ 113.386 764.2205 null] >> endobj 22 0 obj << /D [337 0 R /XYZ 113.386 462.0483 null] >> endobj 26 0 obj << /D [337 0 R /XYZ 113.386 364.0978 null] >> endobj 353 0 obj << /D [337 0 R /XYZ 113.386 301.2075 null] >> endobj 30 0 obj << /D [337 0 R /XYZ 113.386 208.5949 null] >> endobj 355 0 obj << /D [337 0 R /XYZ 113.386 145.7045 null] >> endobj 336 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /ProcSet [ /PDF /Text ] >> endobj 360 0 obj << /Length 2152 /Filter /FlateDecode >> stream xÚÍksÚHò»E•¥‡žÎÖV#'ì%°är¹Ûû ƒÕ‚„%‘ÿýõc$d‡p®«ýpE3ÝÓ3ýî鑸ÉÂÑ®ïßu”Þ`¹¿ƒ ,¾»’†È¥ã  \Gønˆ$ƒÇpŸº à»MñÓd¯ãòêþjp:P†Näjo`~è¨ÐÓHúvqõÓ A&'‘,ÖƒH9¡¤‹©½`°XýËRCÄVÏ›MçñÐÖZ[ãÉà­»8‰§8¹J+ÆÉœ×ß"¼øL(¤ÐÚ%Üd:f r´£˜vÄ8mMùií 1ü÷â׫xÑ)ä‚…Âè² Ý'"••è«|òˆôWJÉ:ƒpÀXƒ<@`=ØË€i] Ì÷-‡€”þ0šÏQl³².‡ZXÕ>«*¦É ^x‹DØ@JŽQ%0¿×—E l%/r}ânºV Ǹ"²n‰°¹X…ÖÓþÊ#.†ÖL 6B 4Ï›-ì¤iÅè;Ü=K>Æ€O’kf±®*÷ °¸è„J³/‰ï>¡ñøšë 6€*(»ÔŽçFŠdŸÎÇ@æ°–/,î;‘ö=ÒUF‚ƒlT¤»§:‡=õÍ9Óx®£•t Róß…ÔYE*°‰ Ž4œGYQ[Z‡*kÒ&/iYYåšÉZÛèȵ²Ëm[Œ‚)S±ùiãסçY)ÆÃÑl㣅€¤Å¤£¼ zn,µ.9À d#`…Þõ!ÒØË)E= QWÜ™~c4Ä9¦¨ëÏ{®£´áyw,Ú¬l¶™Ù *Ï]n¸“5wíLý»ðÐ7ÛÔ“×<esÎ÷5«õeÍV°[rv? )n9Ó)ËÚP—;ÞRÕœý)ú×(nŠ.'7“xM¶âÅ5ªRñüWÀSî M¦gc3-t¤/¢~º»&Ý »YæÅã1«ž8‡mNá:š?ä O8¿«GŽöéׂÎÓ¦$ žR®y¯©˜S¤TÕØ1tŠšÑÏ’—Æçk›¥ñ‰Ž f#…WÖ°Õs 3³JP„^“ÇáÿÇ÷ÇS]‚2ÅaÀfiKš¤(#ÔÃÐVTÑØ•Å&3&„È4EÖ“x¥øP‰vÙdM›Ì:ðXQRp™1äŸ1žÎy²ÍÒ|!}k<ÛµêmY58Õ çŠ'm1;Öz¤ 1ÔX‘Î)œ÷¦d!bK— ÏSöé·|?„$Cí·ËŠ p NXspTžÇ‹ÆµÃ¹»ØbP©"™‰á3i‹i¾†^Çâj%¦Va8Ÿ¤IêÃÎ ¬®__xÖ ç»'&, SbCJò‚9œ‘挪%éGÅSKÌ–h?†ÊÜk$‡Ïa $iQÿ9¤s 6œQðûúsmcÛfBÞ–W,k¾¡„PSXæu^íõvʃ>¯y¹G…Ûþ@¾Y¡ M†L%°úàU”ÿ“ÒuC ?_“À)·©I"»éByÃlôÿÂ@ Çeã=þ ˄ɲ×w+Æ@BØügõ*á¢Ê—é]« £–ieœ„Ў̲i; D±Ò)X+UàrÖ!¢'Ú/QCAk].p#íòŒï>ŠkÏš˜“Uº Þ©äKâÌ‘ð—Õ6=õ‚˜â‚¯K)Ç´ö_äãŽTNJJg¾ÉÉ5u{k ¼Ó}guØb.¶Àê²ImŽ‚Ê+ÔÑSÐ,´æÚõ­6ÄjJÞ}6¯Ï)Üõ;¨IgV„!Ê#ö5+†Ò¦Éö³”ò°¸ý '¦G wæBî;„ýÞè1O•@Q3l´ìÚŸtÅR…½×óbÓcî_¨]ȼ1éÜvÇ:ãlŽÇ”îÂd{ÉØº³“é$^D/¢^VN» y?)Ú’‚ò›jÒ]Üm™¡`)Í5N²´&©òå÷÷pמ¥d•²ã‘šºÔv|gïéS"sËö[¯{áÔ%ø{7´=¥°ßÁáå“…5ÁSښϰ½1š|³øÀ€‘‰Òc³å6ºM•Ñu¶ìat Ž‚0ô¼šáæ^ûŽïûásÃc¯Ò–Ĭ>×zØÝ¾~Sµèjÿ©€£ ãº?»—“1zZÿAA¼áõ~÷ɽ„&ÃÀ#ÓŸ¶ËíRîÓ¼%ióüî9…6F1P¾v·Þª½yú/âÈ…Ç®ŒÀ6ðf†{¾ÿ$þîiÜÛ}jz{j:‘ÏáþÓ¸#ãž zš›. Á¾^È]ô›7è/ϲùå}<ÇÉÏ?ÛŒ)Ër•Ý0pÿ)N¾\ó¼êá§³8If‰YÉW-.±ZïÒMm«ozlÌ’4‡Ž¦óÏqÒÜ"?-ÞÏ’ÉâËKüx> endobj 361 0 obj << /D [359 0 R /XYZ 100.3464 764.2205 null] >> endobj 34 0 obj << /D [359 0 R /XYZ 100.3464 727.37 null] >> endobj 362 0 obj << /D [359 0 R /XYZ 100.3464 675.6257 null] >> endobj 38 0 obj << /D [359 0 R /XYZ 100.3464 617.6392 null] >> endobj 363 0 obj << /D [359 0 R /XYZ 100.3464 577.4598 null] >> endobj 42 0 obj << /D [359 0 R /XYZ 100.3464 429.4774 null] >> endobj 358 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F52 366 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 370 0 obj << /Length 1457 /Filter /FlateDecode >> stream xÚíXYoÛF~÷¯Ð#„›=x:iƦ ÕHJ´é-Ò™tHÊG}gv–¬$˪‹6 zàÌììì7;ÇîJ 8üÄ@ÅTà |ÏaRrw0¿:⃌½9FÇî”ìM­×³£çg"ÎBŠÁìr Ü…2ðÁZÀdàªÁ,ûÅ’C[pέI<ýqœLã¡­”²NGg ·ÎâIœ q2VŒÄ”Æ_#?;×"ÔPÊѲQrJLÈ“¤‘LY –ÑQŒ3àøð×Ù»£xÖ{ä„ ÝÃn÷Z{üv·üVœ))Áœð˜#„Ð~Ges;”•#¨š^šºº"tÉ&Òã]Œ‚û,TÂx!8ê†[†¨Ó¶7Õ5VWzž£¡šPöZˆôÅ‹¡íJײ_½zG§ñäåK›$Õõ¼Êòcb>~Š'_ž]oȓϧãÑ(1CEfäÒã¡‹nD·Ë ­õ.Wé¢1Êßjú¦©Y £ï‹µª0 EÉô<ž!foÇ“Ñìòééh6'ÑûnÂ!d°Üµ‰›Æ'Èô¥ªØEZ³¡-=`G˜²ÂåÖtuÓ¤`¡ðƒ­iäÃþeöêwîý92€¢<ßµÏárÐõw`Ò”ÕUÕÚM^ßäuÃʼed»lÚUÆ@X4Å¢´08‡Ô–ÿÊݽ{(9÷¸/.L\©°#<îôB l‰ƒn÷Ñ{úV}\çõ=‘mqÕ%«g–½jòù¡xNãÉO}r éC'áLšqþ6NŒþyn²7Z/L-(cI»êX¸U‡L~˜¾1hF?c'„‡Ê»é Ú*Î~~&ùV;ò xж”b"pL3JW÷MÑkŽiÎv sè`Ð>¸Ö~­»¬”ÒšcóªJ˜wYÕW •ÕV4X”CZ­ip‚ܱ‘ΰ˥ØëZRÌ g§e†ŠzÆmÓ+—–Üi¤š*µ³¢¡Õ±‰ÞèN ñÄݲ}ÍËaÓsPjзËbŽZKHq.­eÚ‘¶øÔKZé+ìÁÀ•8¡%½ê’¾sô.°²œØ,¿é»øªº§–•!°&îµz«SZ /´½\[(Q$¬ëõZÍ3E£lÙä §Ÿ°>-6”)H-Š›¼!25:éº]v8 ‡Y!g˜ù œ‡˜éCü 1å­7ByÌó¼`{;QZh|{Úî§HÎ<8˜© À¬ëYYñ• Õç­‰Œ lÇt}‹,kuÀeª3±¨ÖC:Ðaª‚ˆ“÷ÑÏó¢ä I¾Aÿ)pK¨c e euò»¢i \uA b!PZ¦ZÜ÷­ vrOF˜B³PYHHJ$êüzuOä-ZE‡0¨E4pQ´$˜¯ò´Î3êÀj=PÔÑÉÕhAÐÀVçëXÔÈc!”w›.ávn¶ù‡‰í梋ˆNeÝ”ER£F ÖG€kû}3sByªONõG”¯uÙQ¢:hø%éu³'HT% ¤èWF´vc¾Zg; Ó}nMǘ0•&îHŸ$£Ä´¼VuW¼¦AAýþV•ù3"ugØÔÓå…ßµŽhUëíHÛ¢kT8 1ßí¦u•þ|@¬\×ëÇuçš»ü:ªpzà:O¼Žnª?~íµþ‰ëè8žLÆ“ÝÛ¨PJO½þÝ['ÿ—ne³J/V¯ÇÌ\tûÑ»Ÿ÷õÅ>øÒe>—êiOSI ÖϮdzC*Žf'xbvlª?ž½Öw|¬ü¥ôØ}¬üW)}ºT¥Ëÿï”ïöNÙª—îY8.ÿ벡´ïO—S'xô= þ•8endstream endobj 369 0 obj << /Type /Page /Contents 370 0 R /Resources 368 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R >> endobj 371 0 obj << /D [369 0 R /XYZ 113.386 764.2205 null] >> endobj 372 0 obj << /D [369 0 R /XYZ 113.386 497.0765 null] >> endobj 46 0 obj << /D [369 0 R /XYZ 113.386 442.1829 null] >> endobj 368 0 obj << /Font << /F18 200 0 R /F15 235 0 R /F52 366 0 R /F20 186 0 R >> /ProcSet [ /PDF /Text ] >> endobj 375 0 obj << /Length 1968 /Filter /FlateDecode >> stream xÚÕXÝoÛF÷_¡G .—ŸNQ@‰äFE#×’Š4w½š¢mâ(R&©¸¾¿þæk)Úa„öÞÂÙ™ÙÙÙùøÍZjâÂ?5Q®ëh?ô'Qè;žç“láNîAøÓ…%;VŽïzÉÄwÜÐQeò8q($…žþc¿Io—{o2¯/n.&7'ƒ*v_; cÇ‹ªï·o¯T >9‰›¨Éön’xN¬]Þ%ŽÒA4ÙîþiySÜv­õbóëõj³˜ÚZkk¾¼¾uµX/VH|˜*kĆåïq½ýL,ÔÐÚ'Þr5çEâhÇcÝó´µbÊí¸¬Üé¿¶?_,¶ý…|ˆPœœ¢èØC%ºràM !$n|Jˆ _)EW~÷nj^`Ýóæ™É®Øç—LºüÙ·y†ŽÁq6Æ0€Ó†›?\¬dÇç|ÇÄìxÏ„§ù«ôe_J¸®ž3ùió›å?0²nàZMöu'Ç(WãnÈj0Ì*Ü,Ñ!d_»Nà†!™œUíÓÔ‹­CÞpøï ÖM½çد†y¸|ćàªdêÀq£a¾I„QµOºgò JÃ[Û?þøq1›/Ö?ü`3§>dõÎ¤ãæ·Åú˦›õûüúÓl¹QÑGIk/>å»2½oEù±áï»ÁYÆŽž­6ŸkS†ùÛöãõz¹ýòš?Ÿ/·ËëÕì—¾˜ÎxÇmP[’¾ø€‹Ës;ª¶Lo[§9ÖŽÔÇlõej{!VÏïf§§œDEñ‹|ñ“FõÍ ÿÆ–þò}ÏÿY re½½òÜÑô='P±'˜–Ïm]Ö^޵mà;ÚS>8‚ÚWÓØçfM»#ö)ОZõ~ë=+rž@Ìm³¬èX’VxJ¸õ›VøÇuƒÎtiW|%qùÌÛïꆉ¿Ì6&±ª0Jv¤/ˆ »•v?á«U‚¡]½O‹Š‘åñØûDAT댅 ®}'Ðpq>0%`G"¬[û6Ý=BI g$°¦ Tí¯¥] …:‰,?/AHÃ- )2Ê:”äL˼§¢{`Šl"‘"Hö&Cˆ®dÑRÒ¥ð0Ü‚ñС†aü2Æa /œ6’k»ßçA…èXÓ>ΩbðW|¥À1Oü "Ì«|_a:ði†¬÷üŽùÝC*TÆñóU-¬[H2©ã9¤ •M¾Ó¡¶j±¾«YS\ê °'ÎôÒ |2„·,¥åÁ°™Ý Åÿž[6vŸWy“vy;¼íH5“o^Œ‡\T¬»ú@¦ØÒ÷}¸ž/Xëèå}ÝvP÷#N¯®·ËO¿Âv/ßC7vH„Й`åzýi±^¿aÑ-hAK±Zi¼¬™Ac x0™˜Ñpõ…éÑ~ÿÄ+Âö+Ë1»¾õÛœ'÷ÀPÑËX”6R¾@ïÓ»\Y{N3w­é^¨tÑ£¤rr¨ƒOè¦|tEÞX>Å”ÑQÜ‹5Ç¢0Gaq•9ÞŒõÉADt f!Hy9¸™XÆÄ×ÈíX …6¼*é­¨~cˆgfRýgxqn¢î¥;Šßö) ƒ„ü‡A†uìA]PàÀA€v(„vé(ÐAT±9/°Bä`€¼FÍäw®„[j!tãâ!EïܤUËÌ'Ôî+s+IÂP)äÈMîý OêòÝXáIÏiÊ~º&ͤf0Pc3€¬¾a‡> endobj 376 0 obj << /D [374 0 R /XYZ 100.3464 764.2205 null] >> endobj 377 0 obj << /D [374 0 R /XYZ 100.3464 463.3904 null] >> endobj 50 0 obj << /D [374 0 R /XYZ 100.3464 414.4339 null] >> endobj 378 0 obj << /D [374 0 R /XYZ 100.3464 269.4894 null] >> endobj 54 0 obj << /D [374 0 R /XYZ 100.3464 179.7608 null] >> endobj 373 0 obj << /Font << /F18 200 0 R /F52 366 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 381 0 obj << /Length 2309 /Filter /FlateDecode >> stream xÚµYKsÛH¾çWèHÕZ ß"çfGò®·9%+µ™šÙ-Rk%Ê!©qi~ýâÐ-ʦ]É!I•ÙF£4ž-äÑäû¡¦ÉhšDnxñh½{çhíŸï|Å™¤IëjõîýµŸŽ|ÏͼÌ­6#?ÎÜ,H§D-uƒ4G«â'O|Ïóœåüîóíân>ž„aèÌn® î\Ï—óƾ3ÇàNÖ¯0_ý‡AÀÈa7‹™L27tÁ½Xè,„€ï(Nèz.ͼñWÿ~7_Y‰¢,"F³øm±-ÖK¹ïLn£D?q#ß÷El7ÂÙ>±Dâ;ŤÞwÕæHŒ%Sg‚OâÕŸžVÙ€ó²îdyq»Âü†V®(%Œf?=§i! i>îsà&ïú¾ªüJ´4Mœ¼.d°0j¡ñCõ×8 ’˜M‚˜g6eµN0qjCë­ nhHs^bqh~”é÷Ä` •µîxOCgõ­¤–¥läôF‰æàcÜvyÓ•D„L¤×8Ê–é©ê¾áø±$I*G™¬Ax_Ó: =€—&ï*‚ÐrêlÀ4oZ3fɌП`ê9ë½H 6ö[Á“YOÈ4tHš(œkŒ A©÷ŠéNänó‡²wB^í†eÊI–($¶äó·•‚vG‘ç°Ä©jå{¦Äâ‚€IL®1QßJËc÷À¬)»„«[¡ª§-nábË%èÜ.•‘º}S"¯tÙ~¢0%û™ IÒjŸAs0ié´¿¬þå Ôj.J£¾ý`ÍhI{L'á{r.Hç ¢õކßXA´ZéáDY­Ø#á{÷BþéÅ^UO/¥€G4.ÛåcîªÅEÆ­8ø#ì4L¼šZ½…ž)ApÅ!«úqÊÐ9i‘ |ÑìöÓåͯw7 ŠOAà†Ó8fö/ë|{láƒíoC¡"ŽÜ0ð#’سr“Ã[¶P™ÀàAy`VÔ‰(ªQ°÷ ÅþZÙpwT$è“Õt©û:x?POë{<â€5ìíã8qŒÓµ$ÓÌ*˜,_Ödê»A<ÍÎïl·Çq,ÞÁ¾\±«w°=?¥ÜBwÚ°ÛÆ‘Æ §þ¬³ÜPz&¯ÆÅ qi XPÙou{ÇæÈœ0UØC!ªßÁ3ÙtbòºS»õA# ë =7Œâ¤ŸvM;õäðHÆDûsÐéåÉ•3$%ÃÖ™¬A »Çm¹³é©8ÖùN5Œ9ááVÕ› Jî‹"A$‘ ˆœ/ŸgPí%œe5¿à‘íä€I(וײòPv2`n+¥’Zr¹€´ùÖ3Ÿ½_|].ïY½ßw=<2º·³¹Ðß4ûÝP(vxáœ}!TRõ'}þ(à §’àÖmþ*ï]ÜiáëC´WHP¹BTrbšÝu®’ï‘XE xd†µ 2}r¿£ Õèî'»"lïÅ”&b&ªMcn’†ÏMø„kœLbßG‚\ý@Ñcm* $}W2¶¦„‰5¥  §q‹WÊJìc Ý7Ÿ>ÓÁ‘(NÉk™$ ÷½ŸJÉæf´±W£ØPê_e¢ëh÷M£ˆäÇidÕ ñ¬udN'hß‘Ïʦ2Û¸ˆÂ6®JJ²ž Ÿ:ª ÑixSÔ²Z8 î®)ófàepeþæ:ß×¥6ò5‡>uK\7ûÞ︨9ÒF&†#&Ø îþ^’2×w*/ªLFº‡ÈG/¯qƒõ{#©0”O_•®<MæÃ§õì–m© ™^ÖqqZ·›R£9ËVý´– {§i—˜ïNzú‰ðÙ®ã/ÊÔ`ŽÉ™è_$§uɦäàMŒ:eK%æF8K»ÉíkœÀß½Ò¿ý`#Wc/„‹öZCש`kÌÝU\ø¹ZÔi!ؽæÃëÚFÚþü Sf jèžþe.Iù‡L4óDx ¤º¦ºkæ¿d“ׇÔÁ—ê´+Cæ\•É  Šu^‚qéÅ-Æþ­âj½ÍÛS;GN÷Í–/Ú¶½rî@w)}`kšÆREËt„bõè.Õxì™J¡³†Í³±5‡ìÚ×½-×]?„šoטìZ›t’¨P Æ JêF¬éCbì…¢‚cÓrzÞd2ÈúÖY‡¢D¸‹e9Æ"9ȵÚR´0fy°…»¦¤Hâ) ™WVÈ­ ˜ÒkQ Ô[o¾<Åcí¸G‹XÄÊ_1…F͈»%ЊRï2ºçŒÜCÛ²x¿¬ìæ. œl·20UBÆÔÇÈšéüh|IÿdT°­ä2A'ˆâãJ.o¯ôÔ?@/ÇkǹžØ¿I„ðz[_çr›Æµ8$&½÷#„ãª^oq™uÂiª•önÏjE¬³íÌÓ Ô×Bìôò˜¾èS.$4é+%—%¶l(­SýfŸ½†ì#X–j¥·+»jgmÀ'¡0Ïì;Æò~,¹*À¬ ë}¾Ñ˜ú±c+ȶ¼KÙØ”ò¨€m…=R¾6Üú‹ë¤w¹êËRë×ÞÛ)]:åYt[W0e©vtõÙ[Bñ4±´)7(dÉÃùÎ_±O}«¸0m) ½0jbg¥††Kí×ç3<5rþøSw&çFP `(¾¨yG«ÏT51Ü/ç×4ûÂzD/òcðé‘ «Mù¸­ú/;{29™/MjŒ•ž¯>³€ÙB±uN^œ$»?‹åîóß8Ì Å€ ßþa§‡4ô»Î3R`ÐýG•ÿ&Ägäendstream endobj 380 0 obj << /Type /Page /Contents 381 0 R /Resources 379 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R >> endobj 382 0 obj << /D [380 0 R /XYZ 113.386 764.2205 null] >> endobj 58 0 obj << /D [380 0 R /XYZ 113.386 727.37 null] >> endobj 383 0 obj << /D [380 0 R /XYZ 113.386 629.8135 null] >> endobj 62 0 obj << /D [380 0 R /XYZ 113.386 586.5247 null] >> endobj 384 0 obj << /D [380 0 R /XYZ 113.386 531.606 null] >> endobj 66 0 obj << /D [380 0 R /XYZ 113.386 499.1392 null] >> endobj 385 0 obj << /D [380 0 R /XYZ 113.386 441.4932 null] >> endobj 70 0 obj << /D [380 0 R /XYZ 113.386 386.7765 null] >> endobj 386 0 obj << /D [380 0 R /XYZ 113.386 341.1645 null] >> endobj 74 0 obj << /D [380 0 R /XYZ 113.386 270.1714 null] >> endobj 387 0 obj << /D [380 0 R /XYZ 113.386 213.1314 null] >> endobj 78 0 obj << /D [380 0 R /XYZ 113.386 144.2595 null] >> endobj 379 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 390 0 obj << /Length 2183 /Filter /FlateDecode >> stream xÚíY]oã¶}ϯð£ ĪD}÷mÓ8mŠnÒu Ü ÜöA±åDXYòJòîMý3CRr¬l÷è[±ÀŠÉáðÌ™¡ãÏ<úçÏ|Ïsƒ0gIºJyÑl³¿ðfO4øã…¯•©ï†žÊf¡ëÅa •Ù§™ç&1+ØÉ?ÙIZðÝí^Í®›‹³Â~êfaÍIœº*¨^­/¾»ñS²Éͼ̟­w³L¹iàùd]æúA”ÌÖÛÿ8j¾ ³=gµ|øõþîa9_Aà\ßÞܹY®–whü0÷%2~…þú_,‚F„,»½»–Næ®Ýw" œ;YÀw´Nàz.õ¼ùïëŸ/–k{ <”f_w¢ÖYŒ•øÈÊÙ÷ò9;ñc7ô}ŸÏü®Î«—®¤½»ï±99*ÏŠB7P~H;A{ý\½aâ´E‡4Õç¹J¢éc×K¯¬»Ã|¡§€êFK{³Ä§cѾHóöÚE#vÖÐ|&cX ·ÔiôòÞ’—ÜêEmƒ=?ã[²‰N@Žð]%ä?p£0SlzwüÍóc^¢,jL‚A‰Gfîx}Þ—MM†DQì<õ–¤eý%ŸtÉ®BÚÏE¾åS{Ÿd`ÙNDwæZ©Ý‡ ˌǻ=:yUÉ1IIìÈiGnôÏìF\ ŸÇ;=Ⱦi MkVèÊjt&‚Wßhì6¤yßç›99î#/Ks\¹íSŒÐVŠ"Èó 7*Ò§Àp¶‹ç¦ëë|ýãØYà“8W‚tjåÛm§[¢qgâ$d6Í<àãÒ]ÉøŽ$;€ÌâØò±$oLÀÑã÷ qxeƒ ¨7Õqk}"ò¼ÆWÁ4¨àŠóJ|²ZÉ·¬µÓ ð0íȽ¦-{¸õE4:dZDÍNO5ðßÊÕË÷¯C: )Zýl+åIŽcú,¶òb¬ÍÁ©ÝTL ‹Ø6lkÕàëPxÀV1 ~øI¾Vþ¾R€‘FÄĬ*#Šõ“¿Ìä"ãybQìG÷u4ø,*¡˜Ž Ã,ÕÔ¹mRÑ“j\Uons@£Ÿ<Î@€O5àëŽößGécê!ݪ“(û¨ûæE'ÃzŠtÊ=óA±/ê^´oÿ}³zèÊsc¤âºy€ú‚TqÌnÁF4º3LI*¼*·t„Pk` °rê4ðÇ+ ~) ïÔò9rIðyN,˜WåVKëî è£ÐüæE‰o”úUÞËuõ¢ÿp°yGj¾(ä¼ÛŸÙ‹}Û@ºF21¦³çýúöý¯¿H‡rDƒ©‚Z’žú ¨eûBŠ›£©;€XÃv$BjýroY@ n)£¸"W7µãÐn‹×ÛÖzÁ»{êqZ¼}O-jÂJo§;J†åSýu’WcÌg–äwMïq%ÜjMº&Ì.ÌWli0Ëkô—&J68÷q[è„0šÞŽ &QL©e½ä‚ûÕûåŠW:w$.Úî«Q’ÓAaM_êÄ›6ƒäXj|‚XL¢^7dOêÙH¢ö ä÷bïà –Ì^4Äfб5@;¤W¢ìt(²è¼ ™Ž»,´W/Sb“GŒM•ëP…xê$/ñÖ!EÌ SF+ÚR­qâö_F)ñz ÉÈNùî¨Ë*–s*¥ïòzÎUwÕÛ­ž(w¦6yâ0Ú /CÚ69ô¹0… û37\³C!å߬+ÿÈ+­¼„åwVKÌy#¯Ÿrç \ô-¼ñO­üO­ümµ²ïY}Ì·¸7,ðBþŒò'ZLÅøSÅá9b å‹0–v4 µH€tƪPUHÜaè5‡Bö­šŽ9ÔO¦yÀ7¨ô“³`ba'qªkd?–0¤ï«ºX¯ÕÈà{ò¶+t`Ÿ-¯qÁä– À!½óL ©dâ¿«(xàGPfLSaä± ì¯#ÄÞž¹ ÓP@2—HÌÃa’:ÐíE…ýŒ†©9#óÿ„_ÏÅÉ!?"2Çòîtho[•ämÙ™‡Œ0ÔŽ7'Gr­—·o À¸J³ëPs‡zµNëžò­ê´Ò #.-5ÓAާL߃…TVÊX•? ?VÿO0ú6õÇšëš/ì?ó›*ïpyY†‹Ãç,"#šk_–À?úLhŽ#‘uõ—BnŽ­8êLyHî?’¸£P¹q§§Wtb¨”F0ÕpÜk`.ì"ã0¦ìr2Pi<ޤrô>Æ h!½«4’P„ ÀA-cÚU*•j jŒÎW‹¿`SºZE•ø\¥©ç9äS«H@(AáP¹y‚ä'ßïoÔfü˜Œú0ïÉTÞkxK6ýßø˜Þ` ;½=ÕÛÄm;ªHI|Â:Z¡¡³ÖŽ=²•^þ¡,H¦8Ép5í7=†O¾úZ5~ínäÑ»-¦ßÄô²ág ÜC²¶oš³ƒ^m%g›ýù“`ˆÊ„¶îEÖd¸ä½Î‘¨ …ó­¦ <úÀN214¾Ï«1ÙëY«Õ¹f®Ó3@Nã„Å4»Ð™;䳑h#hÜ—SP7ÔÝ&*È©sýž4Ш¼ZVú¹r)B“[Ж›¡ÆS)U©ž•ƒŒäœ lÕ•¡ o<âŽè'Qµ‘G+4RÇÚú3u¶ÃàÛ¿àÝ ˆ @2ýÄ'Á/(wãÔ`)Õ+NJEš`«ÎÉUW[èìø{­e,¥öqI¢kKÚH?Äçv y°žnõa5uDïyuÄïûGBëIªÓ¿’ Âù7ÊKó‡……ý+Bàü!KÿøÕ5†R쯑#"Ô®p_ÿ 9übH¡¯Ò`ò/ Vi1ÒšøkJ˜P;õ2»|@Éwú;þðSàendstream endobj 389 0 obj << /Type /Page /Contents 390 0 R /Resources 388 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R /Annots [ 397 0 R 399 0 R ] >> endobj 397 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [296.6954 296.0552 321.1122 308.9568] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 399 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [292.9112 184.9533 317.328 197.8549] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.9) >> >> endobj 391 0 obj << /D [389 0 R /XYZ 100.3464 764.2205 null] >> endobj 392 0 obj << /D [389 0 R /XYZ 100.3464 727.37 null] >> endobj 82 0 obj << /D [389 0 R /XYZ 100.3464 673.9767 null] >> endobj 393 0 obj << /D [389 0 R /XYZ 100.3464 606.0009 null] >> endobj 86 0 obj << /D [389 0 R /XYZ 100.3464 574.9795 null] >> endobj 394 0 obj << /D [389 0 R /XYZ 100.3464 519.8763 null] >> endobj 90 0 obj << /D [389 0 R /XYZ 100.3464 477.4268 null] >> endobj 395 0 obj << /D [389 0 R /XYZ 100.3464 408.7744 null] >> endobj 94 0 obj << /D [389 0 R /XYZ 100.3464 354.8969 null] >> endobj 396 0 obj << /D [389 0 R /XYZ 100.3464 311.2217 null] >> endobj 98 0 obj << /D [389 0 R /XYZ 100.3464 268.7723 null] >> endobj 398 0 obj << /D [389 0 R /XYZ 100.3464 202.2411 null] >> endobj 102 0 obj << /D [389 0 R /XYZ 100.3464 170.6135 null] >> endobj 388 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F52 366 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 402 0 obj << /Length 2155 /Filter /FlateDecode >> stream xÚµXKÛ6¾çWø(±*Q”lõ–Íz‹-Z§õºí!íAkѶPYr$9Îö×w^¤äD»}‹áp8ó̓ 'üÂIF~´H&óDûJñd{|Lö0÷Ý«Phf–h6¤ºÙ¼úæ.\LÂÀOƒ4œlv“¦Ãy·…¯q4Ùäï½h: ƒ ðÖˇŸÞ­–ÓYEÞíýŒ{wËõr…·ÓÐ[bãço°¿ù†"Š´·z¸åIåG~ÂÍ7«[; +¤ùLÿØ|ÿj¹qÇЩöS•Æ/ŸÕQ}yX\6 üH)`&¾áÔxØ7UV>µˆÒ~‹€ŠâáªXâPÃ^H½z·¹ÿñ' þa:SJ{E‹ßØËN0vjà¯>5È,ë Ï´Eµ•¦=0.Ìkø.<#ë+\Ù Ïã©4Gƒz¬¦@#׃ezqÜ4(/;ôU£“Ø dR¡ŠHwÓ…öà°>ö> NHx¢‚Z-Ou53ü uŽYQÉвŽ;„–Æš ‡[æÊfÉ_Ãà\ÁŠ-˜f› C²HùÄ;2$á…Ì7Cášâ£³PÙí» €v® ~%x¾ðò3òœ§|<ȸ[fG™ÈMIëPŸxž eOk h¬Î:Ô›†3fØb:ag‰KÛpŒýé,^Fø>w.?¡·ž‚»z¿ÞÑçÍý£h¯NAI`bëÿáÞ7Oè€4ôK€ÈÅzGœ³ä4Y³Û|p¨"ß…ÆŸ„Š)L_x ;ð9Õœá 3u7£¥‰ÖúÜ£A[š"†ì)¸C.äØÙcÙóë>sBÒ'öøŒ<_@mxì/Ü@ixÒ†:†€­£ø=õž Fòæ¬$>ŠsØì,çglGs›ƒõ¥ÁŽYÙÖÜÊ «Ší¹¥/øÂ<ÈKAD«g\»^þ _îהРù#þ­6.Y)~·ggS¯ãÕ;´`Ã\Aÿ/¾ø*ðiøªz_žÍ MÅ0 !ú°‰ŸØÍgâÑO¼ÁE¿ªfJäÄ#»#iÕ=|ÀöÙ4…i_Œ‰ágAq®Q,JX.ÂØÎN:­Î){Á79·u“‹ý`®Þ ½…ŒýUW±{ÝÜãŽ(š@Óg?$u¡f!]–ç¼ßvè=KÇÙ¦—m+©HƒR¶èKzP‹¸AºD$“¯£á÷å¹ÇÐÎB`,Ëø×eügâ8eÑ/¾½`­ûž¾V<ÛØMz-B§½Ê9NìLò=긄R¦/Àið:u>MÑxEÐÇ ±Â ÿÈggv_+ùáª& L_p¼‰LcªŽ§MC5ÂÐ ìJö–ùËÿP¨ç˘BÛ!Ë3Ê¡XUW+Z*GhŽƒá«?šŠ{ AÛíÒØÍ·ìø*¡fAçÿ"3èPÐ Ûõ±™SV><„ˆ_tüÍÆ¼å ýnM1r½öm184‘#AXBè¶6ÀBçî ï·_ »K§N?†»”š°A‡>qB&U Ê´ÕàHÇ);3R“ 0Ùè„BXÕ+‹wÉØz …¦ßš)O$É#–mD}Ž^J¾Ä¯.ŸËòÿ¾¨Nú¢z Ecï#‰¤£t ‰$ Cé^S:¾rÌLDÞdÕ^ÒŒåŸm;Ó°ü£'ñö*e°ØJû_x=\¯y wW©·mawÆñ-VNª€3ö Ó›B–¸‚*(w=¡ cž @γ-¸q6“•Á'XB|BŸz=æ Á'£_3âƒO*pMp+«äJd‹r»¯…öp­>¯7#õ ÚûÂÝ —ñ¾´ Ì3qŒL®QƒŒJYñaêJ‡Ws, aÎÈçZ‰h‡rXcÀVþ nÀG‰!€ôbe”©ö¤+¨jŽ9téÒß²/©{"vwÁ5Þõâà6—¹˜‘¬«áxàÌÅ`-X2¹p'„ æän2ceDLsÖJæ¢Òˆ Û—ñ+€N¼·‡º°õŠ,gýå}iaùQ\þ ߥT¼Ÿ3`A5TÚœI¹"0£…Ôš|÷mDñ{õGÿ’ 0˜Õ‰²+ñi÷Š„kmZ,"Àž_阋{›Ú·ô£DÁ‹Ÿ  i*žák4psXšpüQaiG¥°Ð…¼&Å,í§a” Ê#ö±ÃðUFPžÚgŠGT9c™Š)ÜS´íS—^HÀ€†ørJï\(÷²Fö/‹¶³ é;J!†hHáþT–ÂÚ.ÍÏÏ•Áä?`±‘ÄÊ܃èé|ÄÿG.É{åÃHŒqÒ‚-müsió"%£É¸@è!¹›™«»‡¨ ý4ŽUŸî‰€Æ6ø¼XOülD1Ó¦¬zgóÜX’êŠjôåH2ÜÖü‹ÛÑm!Èä‹¡u=ÂÂÜZÆâšB³±µsÒƒ a'ϹÝã$‘'Oj²j~~‚þðUº]Ÿ1Ôi(¾Wugd’/¸ë¬éư°£§IŠp‰\= ¡þž˜?œ†_þºÖï8¸ÁP~­Œ”Q è%“ô@8ñ1\”3Â×q{¤ QFwâ8îkù*–:%Ž_¸í] âÙ/\ƒ'Þ%ʳY Ž!ð%” ž†Óöy=d§ÑËOð¢±øÏXá‰BõìKøÈŽìˆÆÅendstream endobj 401 0 obj << /Type /Page /Contents 402 0 R /Resources 400 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 367 0 R /Annots [ 409 0 R ] >> endobj 409 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 0] /Rect [159.9655 256.3563 167.4126 265.3792] /Subtype /Link /A << /S /GoTo /D (cite.rfc1035) >> >> endobj 403 0 obj << /D [401 0 R /XYZ 113.386 764.2205 null] >> endobj 404 0 obj << /D [401 0 R /XYZ 113.386 727.37 null] >> endobj 106 0 obj << /D [401 0 R /XYZ 113.386 684.1133 null] >> endobj 405 0 obj << /D [401 0 R /XYZ 113.386 615.4846 null] >> endobj 110 0 obj << /D [401 0 R /XYZ 113.386 555.7995 null] >> endobj 406 0 obj << /D [401 0 R /XYZ 113.386 498.5988 null] >> endobj 114 0 obj << /D [401 0 R /XYZ 113.386 468.1332 null] >> endobj 407 0 obj << /D [401 0 R /XYZ 113.386 413.0538 null] >> endobj 118 0 obj << /D [401 0 R /XYZ 113.386 369.039 null] >> endobj 408 0 obj << /D [401 0 R /XYZ 113.386 309.7171 null] >> endobj 122 0 obj << /D [401 0 R /XYZ 113.386 236.8237 null] >> endobj 126 0 obj << /D [401 0 R /XYZ 113.386 164.1178 null] >> endobj 400 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R >> /ProcSet [ /PDF /Text ] >> endobj 413 0 obj << /Length 1878 /Filter /FlateDecode >> stream xÚÕX[oÛ6~ϯð˨U^$Šê[Û8[†Æio+°îA±åX¨-%’Ü$ýõ;RQ%k‹vØ <$Ïõ;”åHÀŸI!B™h”˜(TJÄ£ÅvOŒÎaóç=é˜&V†‘Pé( …‰,²Œ.G"L 1t¬_v‡ÜÂóííW{ïöFïnJ¦‘ŽG“ÄØPÙX#ë«ùÞóiA§0©ÍW£T…V Ú¥¡Ôq2š/ÿ ôxj‹àdzúöxv:O´ÖÁþá¬Ó“é ‰×cL‘8åýW8ŸÿAKÈ¡uÌNaqŸiêÐ0ëËÙþÃ}ŠPŒÿšÿº7w†Dà›>í<Ç3é3‘©±ì›*••íD&¡µ±![—Å!u^cäå‚°À&6 .p–->æmKilƒŸ˜µOÆ}ñœ®Ã8JÉ-'%˜VµÅê†mþ b¡CX‹€’(O¦&)úˆÌ·?¡à‡’Šk8¶ªûrb¢DYŽ “pjPƧ±²A^£Az•á E¹D¡Ê ÕN³ÄÆÑ“BåcBô]PÄ7yv×þî#Ã-:´ñ æó±ÕàÆlÃRJ»)Û±J‚3ð@rç–jʰzmˆÀ€,ÈIåðŸJÒ8P†ôƒ:Ìv[¼ö±Û4$ æ jô‘ÌÆ|Á”n×93Ð…Ù6çålüm_åJ½Í6Åç¬-ªu“JJEQœŠïªñ^ó&Píȧ/k§d“mÉWNhÉcgÑ•z{g ôåã c$/†l(ÐaäÔ >ȦäKÐ#Q"%=Œ4\¨ `B†i+,Ô‰Ra*#‡‘5œÌ€ ès@=ĵj{‘µj´°!ãMÂ*ÁXç \ ÛUÙ`.icP#Ú›½áùzãÐ Ö[2-[ä`*¥ {jßaÒìÕVxWµè+tMîø&:±€¨xa’ÜÂQÇ2³ätfÐ%rE9ÈtÆC¹ Ǔ؂gQs¢U0«0uq»]g­ã§d«Û¡¸¯jr(0*´æjDZK‰„à[b dÃî ²:gby×7 ´x†;:È6fé £"«.YÈ… 5½Õâ C\fõ»Ò—l5\±Jrú“BtpÀÊ«¢v•qF—Æ ¨WbžT䨀ÍÝb†°†œ9w›Z—ËàÆŠäÉž¦Óëiä!ß×0;¾_k³ÊÚ@YßÛà‘‘êïЗL¨l×2’P$ƒ}éǶ im©ûì‰TAšðüÿ¢cpå£êþkýÞ¿Fø÷5íB»vñûXƒÍ5Wè›E¹ÛžQ“À=\˜ðð ëÛ¥:Až\rÓÈ('K«ÉëOÎÜn ì:FþË]^Ü;àI«=¤qçúõŠeŸÉÄ—¼ó¬¸Ex+))ÄlÞ/¶¿¾ííR>ó•ÈÆ 3J’3¢v©–ñ0Ð"Àë9U?sÒº‚ô*:¸kÖÕÕ^†·ùÒûÌ0v¾¼T&B¦¤æË2ÛÜPØ›Cñ‹£ÚLÖ!÷k{—KT¯ÁhÃðÆ ^WuçÓEËš ¬gkÜ"€ƒ]‚ß ®óv‡Ó2ï[׫†D†*NàkKÀ_a\5D®Ê ®ZŸ+Ô"|ò›¡ZB!òm^BaÞ®ù‡}jº×”ú‚"€w &Bä!’Š’·Á0K~Q ±Æ|—ÁïÄ9N¸"˜Õ9%I»¹Ã!ú^i~d!¯â¡ „KGwÅìx~xôvŒï@šw‘©± qeQQ(–þü3œT®‹Íc ~àA@5]Ä\4gÇ0!x‰IýÛü‡'gï÷€åå!^8ãż®ýþ}•š/Èrõ I¾Ÿ¯2ôÖ¦åçňªƒv΋˼dìR‘ß¹Æç^0½Ü{®íØê(Xð7,Á¯ó®®›ÜÝÐu‰«{…„q¸Mý~82ÿìcýÖäªê÷ërÂÍ´ð7QR–çrøÝãMtå‰öµëЬûœûv@çÖÌ$¥,Yák5vµ÷kµ¸^ÕwJôðýÁ /`RÐGO°Ñãm'pîhzrÒÿò1__ ¾KÅ  ßC'¾áвnxºWÓòs§O5<ìòYä1sx°Cú¼`À„;IRûYûTj(Kñàù›¡º<À­ã“£)œG×(ÑóÅ¡ÆÀ[¨rãÚ-œ°;‰F?‚küæ½ÀÓ·Â sò·Ìý‚/c%á@É0àÐw‹F?¨¢gyºc¶Hs¯×ʘßg°Ñ•#Ð㽋¢¥>‡å+JˆOr $ºhøä–«Í5.à§/ЋºÂ¡.²¶ƒÏá²m«{èyç±Ú¡(\rˆ`ùöÃÉ;Þ‡Kw®èËÊ,2ŽO¼Â Æö‘îšyŠÒè¡{Âû¿ƒv?#°ZÄà¡Ó¤Ç5ð£o”mEÚ Cð§ßÀo¯7þ ¬Tjiendstream endobj 412 0 obj << /Type /Page /Contents 413 0 R /Resources 411 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 415 0 R 416 0 R 417 0 R 418 0 R 419 0 R 420 0 R ] >> endobj 415 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 699.2754 183.6508 714.8171] /Subtype /Link /A << /S /GoTo /D (subsection.3.4) >> >> endobj 416 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [156.234 685.7262 172.166 701.2679] /Subtype /Link /A << /S /GoTo /D (subsection.3.5) >> >> endobj 417 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.8098 672.177 203.7418 687.7187] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 418 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [194.5977 658.6278 210.5296 674.1695] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 419 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 493.6905 183.6508 509.2322] /Subtype /Link /A << /S /GoTo /D (subsection.3.4) >> >> endobj 420 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [187.8098 480.1413 203.7418 495.683] /Subtype /Link /A << /S /GoTo /D (subsection.3.3) >> >> endobj 414 0 obj << /D [412 0 R /XYZ 100.3464 764.2205 null] >> endobj 130 0 obj << /D [412 0 R /XYZ 100.3464 584.5045 null] >> endobj 134 0 obj << /D [412 0 R /XYZ 100.3464 406.018 null] >> endobj 421 0 obj << /D [412 0 R /XYZ 100.3464 343.9702 null] >> endobj 138 0 obj << /D [412 0 R /XYZ 100.3464 308.2981 null] >> endobj 422 0 obj << /D [412 0 R /XYZ 100.3464 245.8435 null] >> endobj 142 0 obj << /D [412 0 R /XYZ 100.3464 194.501 null] >> endobj 423 0 obj << /D [412 0 R /XYZ 100.3464 129.3191 null] >> endobj 411 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 427 0 obj << /Length 1312 /Filter /FlateDecode >> stream xÚíWMoã6½çWø€>ˆå§DõÖ4N‘bá=t{P,9bK^Ii6ùõ;3¤d9•×E±Ç"€Ãáã¼y3$%gþäLJ͵‹gIl¸RÂÎÖ» 1{€¹_.d°‰z£hluµºøáFº™<©œ­63™ÄܥΚãÊY=[å23¤‚}\ÜýþÛòn1´ÖìúöÆÙÍâãb‰Ÿç’-°qç篰¿úƒ†ÐBkCc·ËkßqÞî§¾¿¼»ö#š .æ­~½X¬&5CÔº¥ÐõÆÿoÆI´/ƒMSSÔî(‚Ùº8¡Ÿv{:!V)F¬š2 [­Ÿ=u°¸ò—G‡žŒHC¸¡áë‹&_i9 î_»",zÁ!ô 2ˆV|~î3ƒ4€HLµH•lˆ Ô7ÚCœâ³$`]…Ô“¬ @w[{®`ä´rK¥x •›§<!hóÜgq3·œ5ý—8I½lýTtX©uìÒ›ŸPjLªŠÖÛfß#í@à“°BqÍ40“l¬f%ü*<3Ó˜98rÒËãùÃ&°&kªÅcíHÎ1²áI¬…dVM找œŠ}eXÊyÙ¡l5TÃ1¢íÄC+«â€h¹V“ˆ÷.ªíò¬Ë¢®Ûî ÷UÊž÷t °5b›XöÎ žØIè*ÂtÚ{dŒA ÷ÆúàÆ©‰™t6@µ8¿©:šÖŸ#òfÀ‚Ü–BëK&“*÷ì™Ò?ʨ2^Ç|ãÎÅ tO4áNEÓ'Ë‹¼jÅ©W%ϘŸCÊ)pÕ“jå[ûÛ¬m£(e/LŒÂ¸³ð÷ÁÏãj%|?C9%ïá(jŒP7(Œ>}¥AZö"9±/zOçž8.±>µ\à,M@êDuQdºró:Æ1ˆÆ%$ÔJœ­| ´¦ tëèósÑeÂP§Âÿ ÈÓñŲ}¨`³|¼AŸ¹70ç6¨¢ò Àlš¨ªñ .wþÊ—ìÝiàú¼SÆ1}Ö鶴3(þciúÜM…ÒLžÆðʬæNƒ0ý±DE…QØa®¹LtýµžŸ{›Hö#ž¹Ij<à ùª|šËòy‡[ŸÚQS´²5zõDÞ…¢êÃM›f»þîÚà11ò9³Ë¶å[†O1ôO*Áà~P‰4ßÕ)²ýâ'1E·˜NÁßÑÜ]2ýé80n{ÿȇ•…x*•¦SÞþG)÷SÊá<ñÓÂó(rp"QpZ+eàF‰§^uÑðpp{Ûð˜ç껼í–|…þ|˜øÿyS<^ΘSÏ;MDÝð¼ãï¿õú³XÂ'œÓßþ¤M}ѾƒBÇ}éM~\NìøÊendstream endobj 426 0 obj << /Type /Page /Contents 427 0 R /Resources 425 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R 435 0 R 436 0 R 437 0 R 438 0 R 439 0 R 440 0 R 441 0 R 442 0 R 443 0 R 444 0 R ] >> endobj 429 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.2736 489.0053 213.6904 504.547] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 430 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [198.3948 475.4561 222.8116 490.9978] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 431 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.7584 461.9069 225.1752 477.4486] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.5) >> >> endobj 432 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [236.5161 448.3578 252.448 463.8995] /Subtype /Link /A << /S /GoTo /D (subsection.4.3) >> >> endobj 433 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.9099 434.8086 210.3267 450.3503] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 434 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [186.3039 421.2594 210.7207 436.8011] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 435 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [200.7584 407.7102 216.6904 423.2519] /Subtype /Link /A << /S /GoTo /D (subsection.4.6) >> >> endobj 436 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [202.6372 394.161 218.5692 409.7027] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 437 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [221.4857 380.6118 251.3571 396.1536] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.11) >> >> endobj 438 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [250.8797 367.0627 275.2965 382.6044] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 439 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.2735 353.5135 204.6903 369.0552] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.3) >> >> endobj 440 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [180.7584 339.9643 205.1752 355.506] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 441 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [230.516 326.4151 246.448 341.9568] /Subtype /Link /A << /S /GoTo /D (subsection.4.7) >> >> endobj 442 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [241.4251 312.8659 257.3571 328.4076] /Subtype /Link /A << /S /GoTo /D (subsection.4.4) >> >> endobj 443 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [209.8797 299.3168 234.2965 314.8585] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.8) >> >> endobj 444 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [179.6069 285.7676 204.0237 301.3093] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.5) >> >> endobj 428 0 obj << /D [426 0 R /XYZ 113.386 764.2205 null] >> endobj 146 0 obj << /D [426 0 R /XYZ 113.386 727.37 null] >> endobj 150 0 obj << /D [426 0 R /XYZ 113.386 600.1676 null] >> endobj 154 0 obj << /D [426 0 R /XYZ 113.386 174.1354 null] >> endobj 425 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R >> /ProcSet [ /PDF /Text ] >> endobj 447 0 obj << /Length 1918 /Filter /FlateDecode >> stream xÚµXÝoã6Ï_á—2°æòC”¨¾%µs—ÃÕÛ&ÚâzŠ-;ÂÚR"É›¦}烔嬲èÝ] ‡Ã™áÌoh©‰„ÿj¢¤&NâIšÄBki'ëÃ…œì`ñ_Ê Íœ±ÔÙ$2‰ŠLž&R¤ ôðŸúMžñþæ 'óúâç‹ÉÏ'…ʉ,6v2K'´³E¯Vﯕ›D&35Ym'™ÎHÖeB›NV›ÿEñtfËèvq÷Ó‡åÝb:3ÆDó›kàG׋Ûʼn¦*Z qÇëW8_ýB,”0&&ÞÍrÎÇr—a¾¼›3Ç)äôÿ«ÿ\,V½ 1ÄÄe_›—™ …ÈI«†N*m„N`9U©pÎ&äå¦ü]*S4S«¢¢ZÓ¶;“&Ñ#ÎòõÇ¢CoZø“Y}Þð.4Bi‡§Hˆº6Î4©¯fë}³ÞÜÞ²c?—Vj¶¡@g¢uÁå¤ï,‰ l7ß¡î×Ê6³#è©>Vð·žê4zFj†ÆÕÓ0Ö5 .Ú[< $´ˆ… Ç©ÔèH'™Ç)a³Ñã*:î‘5•wµ¨U'¬q‘ÒÎx­ÊB¿Òª¼Œ|ó„Ê1ÔQÄ ÄÓæ»ös»¥?ÁX›F.FÒ™péAzÀðàmEÆ'? Y ƒ‹Ôkµ.3‘5Ak"ô[¡§ wåöe¨x`¢×•Z%#¯Ëˆ8~C×§)„´hÚ²®ÎÍŠ{UÜ×^“„¼Õt?KÊ^ÉÑlŠÅ3É2ý™dÓGCK§#ÕŸ*Õè Þ;l±©ZyR Ì×_ÖÃÖ¯¦Î@Hó=«¨Ð@t䀩}Où<´·Þâ¨CÅo‰@/×tÍäë÷˜çÆA¾Xf¸4ŽËF­Xxð[ç(´é#…°óIÚ=øœ¢#óƒ/Ž| òÝPeNsÈ÷åŸyWŽÖ¥JG™ŠÓì5‰dÿàELÿ=fƒ·Èob{V!{žq±ù¦ÁL –™Püïñq̃²ÏW´‚)6`E - ¯þ1òj€%2k5"ïLk!…†`4t±Äw1õ»0m=! xÞå³®ÛÐÏêøˆL‰Pjdý μêps^s¼väVÀ™†üB{Uâ×F¬Õê¿Ll›úÀÛî>LŒ.™ï[BpŒ¥ÎÀØRD³8e£K Q’D÷ån­i¤ÍÌú}Z‰ò›ö]O] ©6Å6‹–¿Î?À1?^Þ,™ñ„&M‰–ãb £‹nu7kùž<‰*ÔWÇ’ìÜ8s¬æn,è¥DBâq yÀ Aì CˆFRi‹1‹c8ôGâ6]ââ×òÈÁ*9˜[¼rÚZöà°G#µXæLåí­`âß5rŸÑäâÓ2Uô’”U—-ë>óð0Z” .£-&“Ñ>Ge»¾"œ•y¨‚¥ë¦Ü‘áTUÀXQÔ¼.*¡¡¸÷åϸæj°”¤ø…|„zP™ 'Òœø†ê›1'®ú×[Æ5|l‹‚S$+„*ù~jFg¨Õ³Gš®uÍŒOS›€†cáá o??†# Ä™Þb€|Ù˜ítÙ(s3Ž‘8aÇàm˜ˆÌ$XM€V[òú²Ê÷/-ÞoûýX ZÕ*†`QŒŽ;>ªôxzõúÉÛÖûSFmOÂÈ\ú§p&F.UBÛ4#€KµÒàâ3€»Ï7¨ê *ýe†Æïò{ …M‚lRއ†.æãF<Ü ÷xàK}aæ–õñ„ {Nðì7A - ôÿmPCCòWù.äFçs¦a›}ŸÛR³å0{[7 B’ OsÚu'YþÉ÷°ñ_¯3ü„§–ã¡Üñ[Œ:•2çÖû—^428ÌL/€ž/ÑŠX…ŽÇ¯ÜQWÒÄÉè¦c¼j¹‹4^9w+ ^½Öñõ„{ÓŒÒo~›P•}2šsS‘Ñç$ðnoqõ›!](HwÊ2ê¦`Šl½§7EÑð«o¹b’§ë‚_y?¼•oƈ75? ½übމC׳†ƒ^7›ðîÀ\¶¶Þ)M‡1 …Ã?ã|úÿw7V_‚aù:ÿ“³üÏôµàè É´Ï`Ä6I ;fPdÖ{èU-3òÊÇîË‚î©^i‹µO:žóh‡¥1ŽÁ=tc]]RËù«J|5 ÃýÏßV-óÑü ˆ.PÅ•Ôê_xµ uS{±0žWFŸï¸'à:Òë}Þzö%Ú¯¹‚p ôêm 6‹Šß,¬îØ„Äd«q,}jz«é-r¤j£†RžÌàBÁ·©<€ëˆ÷0òÖ?Î9k‡Ñú¯ T„fô+Z/4H|+ŒS Ìzeh˜²o|¸9ñ/ îHendstream endobj 446 0 obj << /Type /Page /Contents 447 0 R /Resources 445 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 449 0 R 450 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 457 0 R ] >> endobj 449 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [176.234 699.2754 200.6508 714.8171] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.2) >> >> endobj 450 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [219.8401 685.7262 249.7115 701.2679] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.12) >> >> endobj 451 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [172.8704 672.177 197.2872 687.7187] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.2) >> >> endobj 452 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [205.3856 658.6278 235.2569 674.1695] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.10) >> >> endobj 453 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [185.3553 645.0786 209.7721 660.6203] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.7) >> >> endobj 454 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [167.7189 631.5295 192.1357 647.0712] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.1) >> >> endobj 455 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [173.2643 617.9803 197.6811 633.522] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.4.4) >> >> endobj 456 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [237.8401 604.4311 262.2569 619.9728] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.7) >> >> endobj 457 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [189.5977 590.8819 205.5296 606.4236] /Subtype /Link /A << /S /GoTo /D (subsection.4.5) >> >> endobj 448 0 obj << /D [446 0 R /XYZ 100.3464 764.2205 null] >> endobj 158 0 obj << /D [446 0 R /XYZ 100.3464 519.5219 null] >> endobj 458 0 obj << /D [446 0 R /XYZ 100.3464 423.0374 null] >> endobj 162 0 obj << /D [446 0 R /XYZ 100.3464 388.5936 null] >> endobj 459 0 obj << /D [446 0 R /XYZ 100.3464 328.1074 null] >> endobj 166 0 obj << /D [446 0 R /XYZ 100.3464 295.7847 null] >> endobj 460 0 obj << /D [446 0 R /XYZ 100.3464 235.6971 null] >> endobj 170 0 obj << /D [446 0 R /XYZ 100.3464 189.8252 null] >> endobj 461 0 obj << /D [446 0 R /XYZ 100.3464 115.7899 null] >> endobj 445 0 obj << /Font << /F18 200 0 R /F51 320 0 R /F15 235 0 R /F20 186 0 R >> /XObject << /Im2 275 0 R >> /ProcSet [ /PDF /Text ] >> endobj 464 0 obj << /Length 1331 /Filter /FlateDecode >> stream xÚWÝoÛ6Ï_áG ˆ~‹ê[Ò¤C‡Å-loÐõAuäXh,'²¼$ÿýîx¤,·®3ŽÇã}þîHË‘€?9’RsíÝ(w†+%ìh±>£{ØûíLF™q¥®æg¤IÁ QÈÑ|92*ç^x Ú5ˆÞ7(Išª-ñ»UEÄü=)ø†25™â?í‚ñ·‚Å-f2j‡£±ÜÆ…@¢Ú€ëéØc6Vžm`Ü¡Z³nCBOÀۉ଻UÙ‘Ä vÊLåìß WñXðä‚ïÀøVGñm0ÕñllŒa“œŽ~Ü£ÿI ¸ñ v¦È¼Í°úSNb½öB™ ílÓ£B˜—MùðºEÍÛwDzb ×JÈJÏWuH¾`ô•ìkü=EŒnEéB5á,ê† NÅìa…âš×-Ï©dÕË"Ôê±#±çUJ~»W{õPÉ âô%êv@µh+Ô0,¹²y¥¹5=ùûúfêòãí*Ë®ð0TÜÓ²­ºêl¶´¦r)—ÊüJìç¢ ò["©’@ÄJÂN(¦JÙƒ-ú:È‚4°ÿRÝE~ÝWŠPD„åë3Dƒç¨EB tq%ØC }pë³V>Ä }ËEÊ1êhî‰û´fº&ˆav$¸Õ‘ÌÑ4–Ü[Ó¢jq±iéЦ9a€¶žûÆ]#‚èHüÔ/z]²¾eB8ÝôZãTìj «\ÑxšV˪­Â0YLƒáœLƒÍæ–;!ÌéA=”¢A}Ð@?)C7¾È¯?U0v…ToXMRošÕ‚kkóC»0 _ v 9¸£êI†EÎý~o—6º”¡Ð¼Qì6ŠýQ¶In3ؾŽÛ·å–ðÿšy“6Ëqî<›E©é†„b鬆 à"RBË8{>·™[0p-iv!Øm`ÝÕcjùþÜp°Õ©²«7¡¯Á¯e©7±Á¸ž ?3Z̪`+Œ‚º{%æÍKGÚ"U›J.”RÑw׈ #: ìpc)f„¶Dá<}ŸÛÍcèÞ˜˜;šo³® —NÙbÕh^R¬ÉÎA¬·¡6 ¼tVÔ" gS’õÐQ§¹³p呟«®{|wqñüüÌëª[òM{Ñ.ø®òî¥ûU´Æ*ÓGû«†R–Þ½ÕP©S •ÄBC© uÒ꾡Þ0Û7ÔÐîgD7ÿ‹¬ˆX»øï™u¬¤CÕµuj–£P/$ÏMH¿Þ¬Ë0¬ÛM¹O ñ}ä V¯ñÒ­ÖUžRÏ$Aý¼T,ö.¢·ˆ{fÛ†+£‘^nnZ“³ilÀ›Ö Þ…¼ÉceÆødéÊ0_¯ñrWp™O6¨‰^0kÌÑÁEç%“…ÏâT:É”oUþ ž“Œv#Ï ‡%]Ž°ß 2mVü aA hÄ~6bÆ5¼v1ªW¢S›Øæñ¡&<ŠÃ+ºQJ¯©O¤Ï]" ¯z²°{2 (áWIÝs¥—{nžH-üù±»TY”ñøK+mTO:ëãt‡ ½'MO‚„¶XécI—ÎAÃzÿÖt€¼+åõéá0:ò«èGUœî—¿ƒŽXü›d endstream endobj 463 0 obj << /Type /Page /Contents 464 0 R /Resources 462 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 424 0 R /Annots [ 467 0 R 469 0 R 470 0 R 474 0 R 475 0 R 476 0 R 477 0 R ] >> endobj 467 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[1 0 0] /Rect [322.2336 671.2487 346.6504 684.1503] /Subtype /Link /A << /S /GoTo /D (subsubsection.2.3.4) >> >> endobj 469 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [193.014 545.0815 495.9258 557.074] /Subtype/Link/A<> >> endobj 470 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [193.014 545.0815 395.4589 557.074] /Subtype/Link/A<> >> endobj 474 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [393.4664 545.0815 395.4589 557.074] /Subtype/Link/A<> >> endobj 475 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [290.4506 508.7137 495.9258 521.6153] /Subtype/Link/A<> >> endobj 476 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [290.4506 508.7137 492.8955 521.6153] /Subtype/Link/A<> >> endobj 477 0 obj << /Type /Annot /Border[0 0 1]/H/I/C[0 1 1] /Rect [490.903 508.7137 492.8955 521.6153] /Subtype/Link/A<> >> endobj 465 0 obj << /D [463 0 R /XYZ 113.386 764.2205 null] >> endobj 174 0 obj << /D [463 0 R /XYZ 113.386 727.37 null] >> endobj 466 0 obj << /D [463 0 R /XYZ 113.386 686.4003 null] >> endobj 468 0 obj << /D [463 0 R /XYZ 113.386 589.1496 null] >> endobj 357 0 obj << /D [463 0 R /XYZ 113.386 593.6328 null] >> endobj 410 0 obj << /D [463 0 R /XYZ 113.386 541.5946 null] >> endobj 462 0 obj << /Font << /F18 200 0 R /F20 186 0 R /F15 235 0 R /F51 320 0 R /F53 473 0 R /F36 207 0 R >> /ProcSet [ /PDF /Text ] >> endobj 221 0 obj [178 0 R /Fit] endobj 220 0 obj [178 0 R /Fit] endobj 472 0 obj << /Length1 1045 /Length2 4255 /Length3 532 /Length 4958 /Filter /FlateDecode >> stream xÚí“y<”mÛÇe/{vE–cŒ=²}'$1Æ0c™af0öì[d_Ë"Kv¢…BQ–;Iö%{ˆ0废û¹{ïçÏ÷ýëý¼×\Ì÷wçïüÍq#,hj!©îŒuB°‚$X ¬hYZ‚¥°”´´°°& ' ±-8©€eu/ #€¥•deÈ/0 ‰õòÇ¡]Q@TSìg‘< î‰Ä¡p `' ždܰÀ"ÐH‚¿ îá˜ÿÜÌ‘x$Îé,EÎhpBº¢1t Ÿ™ô0.X@þOÙÙÇë¯%_$OˆþŠ)C:c1þ€3Ò…dŒ%Ÿ†$gù߈õOs˜‡‡1Üó§ý¯NýÇ:Üíáÿ¯ ¬§—‰Œ°ÎH查ÖÈ?Ã!Ñ>žÿ\Õ#À=ÐuŒ«þSBãah"ÒÙM@ ÎùKFbœÿ™Ü¹_ @ú–0}-}‰]ê¯ES8C°ô÷ú·ëÏê_ þ›ÉíÁ¡‰€4¹¿`r!ùó×7û¦A`ÑW@*Àq8¸?y|ÈÁãŒ$H"90H ƒ%·äž.XÝÏ••@^äKÁ:ÿÔÿ”äÞŽGý­( $û· €°ä¿ @ù›"€\°>¸¿Y@ûþVA6E`=Ècô—¢HvEü›Àäß Bþ†?C²Ÿëo( €P¿!¡ÿFòhƒ°¿!ÙÊë7$ïÅý†ä–~Cr*¿¿QFá^º†–() HÊ@ €< (HKÿ·2„‡Ä~ý¡Èƒó» ÉS†D‘ºñ1,B9Ò-«1úAˆö½¡ŠSâ'4\›’뻆;è#Þ§œð¸ßgà-þ©Îæ°2—õÌâ©E?>¾=Èì5l3Ì;9{ôÇ¢¯ãbn@ Ív®‘ÿ‚—Ð~ÄêÙ¶Æ‘Ý5è “wŸú¤Û–¼¸»Õ³Zd*ªe¹DýQ¢Ûη¡;/RNÞ–ëaU'4gÊö~+3éÇ”žJ59âCÓ,1ñÛîÃrx¦0í‡ÅâtB¸ŒFþû¦A·Ë1¹’\ “×µ\&oÙsõ÷Ÿ€„òª»sªFZ1ãmûž ÍX´ÖvûSŒfiÄ_s-õŠR)â­×©+aŒæT«JÚMUFLîxʇºQÒ2eÚ»çÒÕòLÖ‘×J².–70ó¼‰àÌÔu.s¨Þäô«L?½T5©¶­Õm¼væZþóó©ßxO´kXÿ`©ì>YI¡9fÌb3[ó*~Þ=¿#Z´*<>âçè €ÞÝÐpV_qcˆœD\´È(¥¬øL3óRR¡à­¸à2:Ç??ôƒt©¢3Õ~´®´ŒÌïô¥Ç1ì¥|8º#e¦wÓU‰ÝE€Á2îÅs°9Äv.y/ÙñË4 š) þÏLHçýû™ øí:pÏž•Uq:ù%†îT¤ú Ƨ£ž.[žu´E…úW¶T?¯”+Þ¾ˆém!vOM€ôƒJ±c5Ñ^«r&'>Ýî;ªA£ž‚YR¬åÞTV$”vU ‹F íõ:â*7—ѹtsëQ ñýBBùìNœW——Æ¡xýØœº™GôGUïÙY/ =&Ñëró2BI¤Ñá3ì­Ò&åþŠRÓíÝeA©é·gùƒ‹R³ç5g²iré8F3¬’<[›¦¥…¶Ëœt-¯/6ƒ]/OP±Øß(þ†éJ7`ä8AñtÒré Ý­~o”Ž·ŸvÞkë—žYZ¹Âcª‘߀²Ê”¼IQMƒ£Â5‹•UåÝ(/ë6µÕ ZIÏ®¦7Æ|·&Å@7?ãgýzI¯bAYCsŸG\6žÍ8‹=þ²Q¢ŠØ»©×K½@bÃ/M%³Ø·?Ó½Cµ}ñ­× ÒI–ô£oé_³O[÷x7VT¬Z\¥tƒ%µÄ±æDw‹~E/^ý’3yS‘Zø‘™Lc¡ÍÛQ'rD½»9~ŠUþægvµÞ”¬ÏkÉ#«V Ýa”@XÊ󾕖˜^$ûŠYÔÆþ©Õ{! ÅãÓ•úeüº7SÎñh¿»_sJE6¸ˆ]ßg¨=’Œ„C¦ù4#ÍDžbx)}ùîV÷Zê°³»å(^¥ ã,˜®tê½Fd}4%Wn燭Øä×ålmĦJÈŽž½@«áLÃV<ëUûœãøÃôã(úäëï@IüèýOODwÅøuOܶcì?ºŸ‘}í”÷b€yÏ¥fá´KýŸ=¢©Õìë„miÏ  z(=¡hdÍøÒ·ÐƒfnP•(8¶®<)ÊýzfE³«U7Lˆ‡*­Ru¯‡÷ÔY±:y¾U%´Üï”-\Í’„b¦Â† ¤oéŽíÍØµ¤¢’µÓðèÆÀ¥4õf¨XÇ<§¦þÒž"é+ÄL¾EdåzI  !¾&'¼AgOœo©4’Y+väiþ1¤æŒ"bóÓݰ³8Øö¤¼ßáøàÁxw¹˜pïRÔ\FèòÇé3Q¬h&Håâ5öãêå´O¯á‘öÛ®¬Ê=±qËUâ…ŸÃC1BëŽ?.¤DÑ@Ñxˆ!wÑF­@Âõšì/ßEofÕkSØ{®G=ÎzDzµ"E\룺ÿCƒ“¢ñ»´ÐÛF¬wñµ`¥ŒSï¿åqê¾yñ¥—$·ÖÀsl¼b¥ñsâٜӰhE*YO¹|gž ·šîÆoi蕺„æ¸4lG#$lë{9v eÌAÌîD©YÝétÙÞ›#ª,éxu±¶¹í¤Cú Þk› éÍëÍ]C¨¥±C23•_·l êøü§Æ”G,ô6Á§ì‹ÃI¼¡rÜ‹)•÷;ç"|ê')·fI|eãu¤ IÊGZ*•©ÞUL3qœ :á¸ÆEó^Š^ëÉD‰gúËãˆnv=m~¡cÛ¨ü–ÚפËr{Ñ@>5eì}2GOK›«màl]ݦ‰ÿ;‰,kKg§Z1ªV½[¹øÊß­I‰MºS³œ‚N™Nµê¬¾Z«"NíöpçR­ÞÑÅòìÐRV¢\ñ’©Å5ï9|ü õRzz:v!+@ã€OÕÍ~=3Ñ0ÿ$ë¯Ø’r¸ü#K=IþJ> àñïº7]ZSTŇ<‰"»Lö1i I„Î9*ýN³Vê#ùn“`áã»*”Ôi0£P)YÊØ™0Ð=ˆŠ­ú $ALj6ï.a³æÜÞ5P]AIôc2 žô§D¤3ưְÂ^–oÕΦ°i ð}º1&?BuycôIšè‹çuó粌Á6¬‘¾6É=¹jÝ?nÊ@~ðp°©ûHèõ+ýišteNÒ7¹ß\áä?k¡p›á·úíöVñ˜[Ÿ“‡3Uð~DŒeê©€X_¥ËK wøºè½­4¤ŸA»ïOî~%1н‰lm¯i+3……I³ôÍ¿q‘PA© D1ð•ã~VƒÝ¥ï*Êî™­~üá’háΖF {(iMñòÌûQ¹ºœÖf/««vB¾tÇëC&nùÂ]± —;Nª‘@’Ã>uü2"/(>&pŒ­õ9qäq­ˆ«ðÛ aßx¬îgŸêÁW¬#Ê…)KIogÜBÏu )€âPpf’5£ïÌÉB!Ë £õýùÐÊO%â'(ŠoØteÇÚM4Óe¼w¤Š‹k³¡­¾-¡$þ#t'?)0‘ÞN5ÑÇP°·”j¸õÁî”0XœÁªØr…-ý!Î.¸dûµEü¦ùý-L­ámï\‡¯Ô!ò¡»$ÅéÍc9“Ìž ûøÙ´ëo;p<ðϬ÷çƒ=¤Î^ß«o¯3–áR#vÆ?æž¿Up¥Ï/KiP}Ó öjK€‘BwwŸ+U=iº´T(P¼Ý|5Ddaé1© uæÂ"™Aû óy_lYLây˜ñ;‘øŠ;¼7šê»ž´¶mŸC…¼2©‘Iã+›¯i˜¬\Žy»§ÑðoõJ׫Ï?Œu¢ûêBÒéö>{ñÛ¥|š¥åh[ëˤtæá!õÍ%vo}Däšv+…’²ÏÛö‘hs23퉷uxgn©KT î;¨ã¼Ðò¶ú뀃|ãÐ=Æ«RzÍ0Ë2®p;¶H?¿šQ¤Jɳó—/Í4rüQÔ¥{ó¥e1ÔíyœÜ2ël¸ÂÒb$xÌ4"Ó—@³é£lƒ¯ÇR?u*óÑVþkQü‹ùGîû}åÖ¼uÁÇTˆ1^Ú­L™F­ög[5Ó “*O¨]îèP¼<®x2ì¨tÝUñsnmŠb»^DIÙÈ<ÎBúc:ñùS±·z62ŠÓø•ŠCFù°¸/[Å™#vÛ\M¬ôD’ð®Šk‡a\ÏŽNX•‘w§¬±,M5q/ý&^t\ëiñŽ1;<šÅý›×-–™KÔ<´Œ~ŒÌÃ¥Âax•æÀ!¡¨d>skÒ¦q›Gtè>ôÁcå/ù}†½\¨pÅþAÍ›¬{¯'ã»Uzv† w»‡@›ÑI„Ãñ[Í¥ç¹>—È_ðœá ¨ Ôäuù¨ÄÐ×ðütüÎrŘ„®ÍÎìªjI”| ‡EïðR™}ª¬ù¨ùœfISB×… öþ] ÅÝ`«#þžå ¿þŒã.çN û5I¹ÞÓļ £Å'lÛÍ­CééÁ‹np+ðÇG¢\O4lö˜Mï‚Ë5ö¢æ®GÎÜ›2ÏÝØôUƒ‰ D;=å]žðyX¬>Ãn¼˜>à¡,¨KŠÇÌ-ÈÂP:¯7žÝ\„@"QYØ/¥®`⃂‡O‡Ý»óÓöyËbZ8_oܳq>„©»º±£ã æè`üwÁ AÑðå»:¶ ±cùûÛkN¥ËCiq‰£(‡­ÌÉz(šïüˆÏYY,Ž[sÇØ1$D÷Ò™¤ä3b€qˆóÖí˜]ç½÷e´Ç'.¢\UÕHæ…¨)ŽÑÃï+‡ó¼›ÎZUyËæ‡AòBRÝÀ‚r:ö¡Ë¢€ƒYò•lßëm£ŒevcšhÍý©¶Ô:Dê:ÝŇÏA+¼ƒ4Ðsi'kzpùH7GI.oýÄ2ëþ¨WÇŒñ=, ú?–—h¹>DòP•1è’ZÓ²4E3e°\ÚUe5½Át+ò¤Ýa;ë9lÚôÞFZõd×^èÎxqð÷³»Œ6W»¾[V«+Ù“Ü’¨*Ì[6Niì½6¹²žN´É¯Q_Z°èŸYüª–É¢X0`ô±êw5–}t̾Õ\Hwˆ;WIå¶Fá×'ºã¸ó­_»ÞgqM j`ÖX+eQÏþ¸[ÐMцÿ&þ­ÍSpýfUMëU”cº*mý-xðËø„Ê'ë³7_Ð źË¸Ú ÖÚèÉ6¥=¢\½rePÆJá,oRŠA˜>LnPôa{5>O _@a¯¨Â¬¥ROŠâ(݇PûL¦R'MÊ%lØŒ¡Ñ}y’áÈKRÎ%Š;ãÒ‰x×{ÒÐâ!ñ¸³Ô5â?ò ŽÁüñ÷<€9ÝP6óºêTÍV‡Lèj£àÁKdxíÑM^½é•h©ìFý'1Om¶…¬ÏŸö9} äñô\NÑä«å DQ¿C„ãÃTLJ–£ô6¯6éw;¾EVWŠM(Ù»´pºŠ®ÎŠo+ÖÒÔT‰_U>~™ Ì jÿ¨Š`;ŸÊ) ‰ør£¢†iv›V7$›«p属T©iTËõLVèêç×ÚÈb*»béPÑUÉv"k£É¨¬<ÏÝtêQàír¨¸4âõ×.;g—Íc«¬«BŽa%ÎT§ö Y® Oá9%„ËèJ… l^¯KOyJö|8׸ø j¿: 8LË>n\L*Š„S{Ç„ TÔìì|l1ê®Ì‡*~Û$€Èp-j:Ͷgb·X:ÍäÀ¼rZúøÐý¿Áÿ „Ž#`=á8wºÿƒöáÝendstream endobj 473 0 obj << /Type /Font /Subtype /Type1 /Encoding 478 0 R /FirstChar 46 /LastChar 120 /Widths 479 0 R /BaseFont /JTFJDJ+CMTT10 /FontDescriptor 471 0 R >> endobj 471 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /JTFJDJ+CMTT10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-4 -235 731 800] /Flags 4 /CharSet (/period/slash/zero/one/three/four/five/colon/c/e/f/g/h/i/o/p/r/t/w/x) /FontFile 472 0 R >> endobj 479 0 obj [525 525 525 525 0 525 525 525 0 0 0 0 525 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 525 0 525 525 525 525 525 0 0 0 0 0 525 525 0 525 0 525 0 0 525 525 ] endobj 478 0 obj << /Type /Encoding /Differences [ 0 /.notdef 46/period/slash/zero/one 50/.notdef 51/three/four/five 54/.notdef 58/colon 59/.notdef 99/c 100/.notdef 101/e/f/g/h/i 106/.notdef 111/o/p 113/.notdef 114/r 115/.notdef 116/t 117/.notdef 119/w/x 121/.notdef] >> endobj 365 0 obj << /Length1 1673 /Length2 9586 /Length3 532 /Length 10539 /Filter /FlateDecode >> stream xÚí—eTÜͶæqi‚»7ÜÝ-8  ‚6 »Kpww'@p'¸CÐàÜ!„ ™Î9÷¾äžù8óiÖÐ_øíª]ϳwÕ¿Ö*:*U VIS°1HlçÄÊÉÆ)”VÑÔr²qèè¤! #'K°Œ‘HÈ)(È ”t6rq9ù„xø„¸xt@i°½;ÄÒÜÂ È Íøg?PÒ±41²ª9Y€l¡k˜Ù5À&– 'w6 ¤ PýO†#P䂸€LÙœœ@SK' 1ÈÜÒÀþÇ‚Èÿï°©³ý¹€ ŽPS@¨IF Ô¢)ØÎÆh 2°¿Cµ@P'ÿ7Lýçâ²Î66¯lÿ,ÿ§IÿÛ°‘­¥ûMÛÚ;; @°)b÷ŸSµAÿö¦2µt¶ýÏQ'#KI;sãß!KGYK7©ª¥“‰Ð â úWdgúŸ mû—v)ui%Mæoç¿ÆT,íœ4ÝíÿYôÏä1ç3C›±t¾ç`ãàà„N„þþû?ýÿÐzeg6µ´ƒž^> bä€ (ñ=9–v¦ 7 È ê—ÍìMB[â 4Cv“‡ÈnoÙـ̜þ ý;Êù_ÑïÞ?a » ØÖÖè9 d·p··Ù=‡ø ¹ÐM›>‡€ì ø9 dÛþa^¨ '×çq^¨¾“ô× . »Øòà†,]þš5çmÚ? µærùË´Aì ÿQ/?ÝÎòo#*´ÿ•$øg[Ëÿ僶9:> þÌÿ|¨ g‹|P’ÏÕ’~&¨Ì3AE^ýCüÐêåž º²ü3AËVx&hEÊÏUPy&¨Âëg‚*¼ù‡  jÏUP&¨‚Æ3A»ªùLЊÞ>T]ë™ êÚÏU×y&¨ú»HÚ<Ýg‚æ=(Ahžñ3AóLþ!Nh¢é_­ôþ9"!´ó¿ZˆÅ_­Äò/„ÊÚü…P]Ûgä„êÚý…P]ð_Õµÿ ¡º!Tòþ9•!´…N!´Î!Ô•Ë3rAuÝÿ…ÿûu#%vódå²rqsC?.è‘ðþÓLœ!ÐÚé_÷8ôÊúo6³„Þo Ȱ46²Ji )óyU0UŽÈ+eÞûº¾ûkZàb¬Mñˆ’ÓZÎ]E:.Æ.â.¥ë©cx»—ڸ왿ClêÜÓ®‹ánºG ©ÎeºŠûŽ=õMàf[ãìc^Ø73k£e‰ï û³ÎŽòTd4÷W¨`zÞ»|îÉâãבM·y\GÏM¥Ž•êPƺꊕ°:ècŠÒ̼|nwƹ+@ÉMx2€¹5AŠà’Ê^lš´ Mg¥`äœ0Ð'Ð1¾;÷ܵ³{ˆ\¨`o.%pn>¾t½`ÜÆ«Äd2“—ï R";ncÕ»‡LÅY›ë¥§Sð^Ð'ÿd1TLâ7µØ°cÔ¿±9JÈJÄæåBDËÒùA’}ŸH»bDƒÛœý”îÀÉ-Q'ÿ3X˜bùœÙ7û‡5æ&çœò}xyë¡ã.¨u”’à•úØ‹“FáÙZÅôýJp.µÔòþ7ÙF%ëlvä K‚‡ˆ8à|Ø´½®tÞõÎZ SªD„°©1ú¶#“Jµ-ÊÜ’Ï ~5ñaG+r2¶Z{Wízc±P Ìòr67ÍhÀ·sj³øæ2¯kb[²cŠåf;òÝK=‰Ã\œÉX÷Ò‡¤!\ì»’ò®˜³Î%ô>x4aZ¢$ÄýÁuL©!Ȳ¡ëNKˆÑß%Z™º3|q2RWßšø'ÉRÅ µüJﯪK …¬3Våwt|ž2]Æ(«'ãÎél +¢0¿Ä*fÂóJ37¢í`Ï z™=ÎSÚh¿ås÷ËQÙõ3$W)$•ý5ƒ¤ ƒ€ÛëQ¡cíÔâZg€ùµ[)ïèî±³Ÿó‹O5Μl{ÈÊV©?î‹÷œ6Œ”¶n-«l©!¿F‚ŠOÑHOçkÝ™Vïý«TašÒ<5ÊOQü–;È6ß9`ù›ý>´w—7g´q2¹j'mw[r±J %·:fÒÌ3ðcœ\ÞÐPm'«I6œå@'?lIL­9†aàjûŒª÷² P•+G@6‡¢-TcêˆW ù9þöFóh8§AÊE014ë¨Ñ·’Û‰éû#6˜t­¦žŒb–dsZFoéîìó1iãøSK©ÕúÃË,mvƒ”å×°Béµ 49Gc[^`4ZÌ3{¸üŠïŸy_ʸ)®¯‡ ¦]²¢øèA0‘ç”ðÖù‡]ŸP¶çVÖ—¹äFÅÄVtÅ]š¯£Ä(kyÁƒv€¾íꔡkÁ®Ú >Û¡î²%°\n­L÷ð‘6»=ÿñÇw0ÆØÝ0Y/ìÛÇ^²¬¼"ëÏ“ú#Gnا% d†½™“°Wû¡Wñuß›ä*sju —¸} _Pº.xD<….œWyz­µcÆ„WAÇ WxébÙI¥5h.ö¸[×:²ÕNüćU‡go·ðä¬Úºüs¾|[Âc4N ó o>ÏÌIgª„ð^Jx²ŒüzJfiÈø|QùÃåh>ƒf¹´[.A6nXsVÈò|¶9ztB³i{2¢àû<ÞSåêjcü鼋7vÁzÖóZDƒ™Ö¾´Á|`Mb^|1ë€v¤‰ÑTdù½·"Ö%ko‹ÿ ¨S²³,S@d–§5R¤Ìy{‰¯£^·]Ž_ÀD;Ĭ|r`%5úª] ýÞ“G@¤WÆ–ªÈfLªJ^NBxût!7ŸÖ §JB/N_zù‹Q¡3\赟’¿…zµúŒƒ‰l(“5!nÚ‘¦b, ¬€—Íå”/¬qœb|¸ªŸø‰e¾Õ/*=0ûí†DûpFÍœ_ȲÎê_ž^8;»¾ÓÏîæ+‰}U‚Ô‘@¡—¿·Šòâ±T ‚%)n‡#ì—]|;ºR;S°E|`OVÉ]§Î›ØëÏÒËû r®ö¹§‘fÖÔG‰žÊ<Ú/w¶äëe¹æ„®î¾ùüx97²xßÚ‚ÎÓ÷¼'¢Ñìrë:vD+r¦aÕ6Ñ~#6~ ^BÎ2€ãŒžð#>~¢S¯3ÜAq= ܳ2+cXOÖþ˜}¨ S1>cΓt›r*¥ïp­ý¦ßVÞ±ÙªTcôÒ'Q¨ÚÛù(ªh³–õ`¤‘Ã8ËŒê×ËhÂ9ö¹ÍðõÅBËñ䈆1Ô¶/uî¨tduÅoøi»oO¨ZßDO©)ñ”§¿‹üá$N»ÎÝ ø^´·¤§²˜®$ºÀIo¢Ââõ,Lœc‘´‹ßËÅ£çá˜ó9äŒ_ìͦ0 $g8&‚XÉ. ‘ó¯øÅ~‡Wq—¶5Ê54nIàá+ ¹´Êöð&3óÅ àM³-£ú¨ßh+Œóôƒm0~gnâœüüÈùÍ2);ƒKNØ0.ª$2ˆAß`ˆ1Ý5LÎçøFùK 9B3.üî+(–Ð&xû@]5ã–í[«rÉ@ÜÍBq+ï<yv<.UH–¦Éš‘•™R< øÔ©ÛIhEÁcÖùöÕèPšîÍíz­~ÒL—ãè%Gé‘ИëJ°‚˜é¬5D]E>ž»¨ì©«BÃ5ª7Xß4QzO˜¥!À7ÄøÖ0†“lè缯çâ@ÅO²cÎöÛÀ4öä T–‘Õ+vÀÜ‘#‘Ìä·ÿpô-Q•»‚÷:¹lH1‚ƒ8 ‘Ì”$ëóñà:O¡tP·ëftö¡[P üLÇ}‹/a¦vQ ‚1{¯¥SÏÐ<üz ù ^® g¯–ÁýBšq{Öüé¾8 ¶óê°¯¾2^ÇÛ‡X—Èš‚MqG+±ÎÜ]K… i0Nûû,‚çÒ@‡ª“YâcÒ>©hûE˜»lï€øÑË4ûµ‚l¼T)ÍžqÄ'ï«/÷2ÙЗzg6¹±ó¯80@Ç<žX³MÒCLZ·1Ébk`4ãwSðÇ®¹ê¼'‘öT¥8NLþ/übݘ㞠_ºhÃ¥|ÞnŽ«]µ?tßîÀŠ¡ÈïâÎ嬱ýÄ»œ\¢»€É´'j)ŠS4DoMÈõŽW«&/I€Y™ÒÜoŠ–°”„àkÌ´‡òu;BŠôÓ<Û±^ÊÄÍ›ùˆX$çàu[É„ûŒ8¼2R «æ9DÃÈÛË,­RêÖØ3¬ˆDm-P~Þ®öìÏoœÇ¨ñ CæxXüJpl€LäÐ7-¡4¥û¦åÆÎ²ps௽JÅë©ýÖâ”OMƒ¢.²Žš˜]g7…M÷þÂxm,¨_iÕ‹Þw„P¶1'5oÁû>‘â¼’ V®û©IH(Šå©»@Ò:án’7ëÜÏJDG¶ 48Ê|ÙT¸„¿£óŠ-诎ªRpB?jôzlѰ¡tÑ2ó?OS 56?ž Šr†°„¼øÄª¦Ø¾ÀÜf.•ø8·¬wQ&¡º)=úSF"”Ê …Új1ˆnWªò0ƒBv£ï¿wÀw:%lÉbê‡í™æœœœhî%ƒÉôÅ ½ôþÌà‹:õï$*(jæ·NeZ"¯à3ñiÈkU–YMŠh§™r_øè\=uÑÖÒ Æ¥ôTòë©NˆÐyÿ Lºªµ5ê(~_J× ùm ly’J‘ÓÆX£Lt§`Â:”S¾§óHø9ŒÐÚw’ò«A©á 8Æ%W«90ô|¿×Pûpú*¾Až½¥4™öm—YfËÇV+Ôf¸§ÉÃ=¾ñÿ;3ÛY‹Ðµ@tÃ74ýŒTã@ìF‡ÆÑ[Ä:DPJã‹9bD³Rú|>Š”¼ü^ò¸o…yΧñ(­1L¥áŽ|O1Á]~¯˜Õ¿ðé!ÏÿJø,"sùNŽu…?qûð öḷ>“ÂOcÏoȨc¦Gd*fg¹Ÿ÷×÷ÙT3ûÙ5v´“½)åtòœ+à N yu\šb}Ö ä\œ"Ë´«9miq’”ÿbßjpñ“¬%ô“IMKïßH¡¯ò|Bø@ŒÙÔÖÕ^‡BTõ-Iù‰y8Z×púûÄiäkÊ`8¬‚ ¥EUÔûÇz•óÌôþøúï°²ÛQd>x­¬}kŸx ?±mÚ8nŬ…iDësY2IH¶ˆ^}•íýôs˜@YnD²iÊŒÇÙ1'+ü€„¼ƒTÓ9&¨Å€uT+⯶‚mÏxÑ^­&î£Ã Žæ±5ó^[e[4:u^Þ·|RÖ±åFuÈói­:jìµ'ÔwV# É‘D‹ •É™uXµÇ ­T.…Rj–!úÝ&:™®s—ÄÄFƒG×W JU]|2äØ ª¢Væ-æ<4²—<§V¶C wžsˆœÊ.úʉagŽ(²Ed^¹ w5Ùå?¢EñÃH}³ˆöá—yÚÌc²e9Æš@ι•ÄL§ Œ§ö]ìm(×Aÿèí ³¸†ñ»l_Oÿ{U™˜§ã}b(*|_ß>É5 ÊÒ¨så'yÊ“Á¦u’)6xE\†.¡>/ËúÛ‘gïŒ@kÊûÑmü•S¼›3FÍLhÊiõƳwn z¢"³Ã*íq 6)¹Ñ(ǰ(Û%œ6É6â¹aM(Èì6%Á¬ÞÒvõÄÖŸo‰£8µ³÷:-öjqóJnÛ†Ctˆ3^¿d0¥!ÝÃÕ²]8à¥ìû1³1©2±„EV¡ž.1mŽª1¯–§Ÿ22åÕ£WöÛ‚·ÈÅìÌp2EŒ¶ÿz'“­ˆVÛ?Ðo®Å7Åw“ õ!/ÊEýŒDY™üÒ¬Þy÷ÚbàÚ–?kX-¡HXYã·è¨Ù}…ˆÙ¾ê§I£aÊÉ„™y×v¾±Ý»lçLz€‚zÄí_™w\lFHeçQkL/þhÅ­K}q0—Ь(ˆ…”=ÙÌj„K \@ؼÿgð»¯e|á‡Í²8·›ßT^t¬€LÝ.…&ïZé­Ë¢¨éãý)Ý•[Ú<¬¢»»¦Ð ͽCj_Óª³„–f(ÊuSà=cÊÛQ0#‡À\s_½ßó/ï%Ú.Fêe‹läÉÜ´¬éÈðñ[ƒ­ÕîòŒø¨ÀYÆêöä”ó=’g‘ÚWj>z(Ê!‰îêÉr€¼ ûzUõ^̹®['þÍ?ìÅ$>"¹ª"øµ& dOäEš0g'a//žû@“PôÀÈÒÆG6py&ºs͆8›s-ÜšQ†c/wÚ[Ï^ðÐÈo‘"UC籋ÆÎù"‰—ž±©;ƒg¤ø* ¹FîïMùM[£]D¿»¥ †ÐXŠ¿ÜjÂMç<íÖ19Õ2D¡?rtþÖD¦‘~.ÀA¸μ“:å®Ü—ɧKÀjÂbM­ó0ÄÃH“­äÐÏbØáÌAÕÿUÍ´\GÊĵøþ¦Ü§öý±‡¿{$wf£)«oO€T¤È1†ÃzÂÏK«jC¿ì0)ßÕ«’ÍûÙ°$…éÁErO_‹øêV¼ñ¡1Í'lÀœhß›%ªO€ÊaS‘¸”µ+ÔYn ÂÌÒ‡*þ˦d,ÚÒ"¬Ç2ªTpÊX28ÒôÉ–ŸÜöá+^ŸR=©%yùž|‡Va¦˜]i®¬•ñ…4,\ú¥œÑµ¾âA—Õæì%Ç›ðFZ=7\£¿•”§´°Ücô¢ük‰a£mÄaf Átk¤Ï[¿•Sp<#X½¿_ $Y˜½ÂÏHú6^+f[ü©âNà0ÏÞÁrŠ6ëÛ=[êΫãó)wWØ3>ìSø‘-JÑy¤NÅ¡ÖPíŒ÷@¡ô¤ßS~¾>£½¦*ê°dM¾J—'ç´ê¡{AgGÙ«syŒôM˜])’±&^Í¥C=ÜØW 0ˆ;…É™¶x©¡“Ó^ã|Óz¬iýŸO ;áFîq,¡§ ¾D‚ÔI/©s÷ig:UHìõQo­A*¬ƒv˜-‡Õ ™ä‡öµþ8¼©4¢'_v^×6s»nN}·Åq3Ã5šÝ·\ËHG 0.ÛïàTÆÜü#UÜÚ“-¶6zNMr·º—´URÔŠoÏv3¦±ä΢‹´2EʵÀmx¬#YmÓc›G;­z{¯g¦¸2t¨XŸ+­| ¿Ì¯¤«;1–³ÜÇÿÐîTz'ND»#Îû† î϶OšY– & ç^u¯qëúº óƸkqx’D]®…È»YçÖ|ù¾7-ëˆÙ âúå4ùJqm·*›vÊýˆe5b[­ªaUDД°hõëiÿ˜|·Z…°å*¡czÔÝñIsõ3ã=ð#®D‡PnUgᔤ¨`ÿäÊía®SUÀ@®sƒ™è\è¸V’÷tvé aú›RUúj¹Ð±YG¹:jQVšA»¡sƒ°|8þ]¦`v†öžaáz®J5™µËþÒØ•úVÐ<«Éš&=i´c;õ±è›)°ØÝ‹,fI´È/âÉŠ,jC°Öïù'½8ƒ|®u™—NÚyW(ß¼_aþù3U`Sšš•>Ùí’EÀOp… Qø±¦ûRkˆMØ€>ÓªÜ}€¶¿w8bc¾Œ÷ÐX•3W÷ü› usÍo‚xêU@·‘Ø+I‡ºÄ‹â„Š£#ü]–çü1‹ÈŠrH}ÌGáZîn$ë3¶þRQ>%qëõB¨¯òõ,0HÌ2ÃÈÈY0™Çê`xŒ6UŽÉQ@M¤š4¦yžŸòØ81Î5ÀsŒ:À쟛 óˆ>Þþ»â{ <©ûá^tsõ&DFi!‡È:ˆg{‰Æ”*ž08‹*eùIPÞ†‡ÊÿñG]Dñ]n…—r®ß¬²ð‚³$³#QCGµBü)UÖ~͸UìPlð\^øPl8©èqÍzzÖš,t¯•BþË!®}îGA`ùz@xŽÖ=cÓ÷㟓ð7‡9œ‹g¿"©³—ðY6ûTzeÔ„^¶£š©\æHÙk‹òU¹0ÝÐ(ø´£Eæ›AѳN®Þ#™5[J}¬Ž)3LH¢ŽA‡åóÕa'H;bØ.÷–6±Å²$ï‰^£Ü¨ \õ×¥ÛéQ‘çFM°(aï¸|] õøýÝWÔËI®ókBÖ‰HŒ¤”Ú&p%zúÆ0ô¬uPG•Dë¬ën?± ¡,ÅJQÌõÓÃ}¤—'<ÿ™Eâ*CÃÚFw ލìP¼ÜµÌTÅG2QÛ ªŸ¼‰Åú…s’–S†Ÿrªñw’¬Ëø0%<£y[å4¿,nT _Ë=B‰TRÓ¤TŽÕeøòœÑÔk­› %púÔ;¦gxWUÁÅWéè¾âïHzÅ~xú`pÎõ“øä1 -ÉÉt öEl'Ç“±x1¤Õ ÕÔ”_¾âÏ û1ñÅ]b%ªÈ£¥÷ !.®Pclêfs~5èiºk–ÖÉöeËÛžŒî$GÊ!"Ö 1Äcž×ëDŠp[Šï[±h´…Ct‘Ä7lÌÊÞs]â œ[Z–òh3ÏÕ¸­ÅsdÃð{bù?¼>Ò°ˆhÆP±övÌ!òCÔ[õ'±ï2ßeN¾%BgX(¬ž™4*:lÉ44¢F[pN¸ÅÞ1¾gš Ps¬ýÅ4ñr¡n£Sñ§žðº¯µÈøÞ#ë­/äòÖÕ ÍC>ÈA”ÊTùà­AKV7U^¬Ò=WêQ¨G%ÌJ.ŽBYâgcQ[ï:Þ'Zùaȵ.SQÛ ŒÀù‰Ÿ?y‚ªz-kÏwõ"=§Œˆ1§Îd©\à\=íæ ÉnÂì†þ ‹z$LnC‚jÌEe—¼¨ÌP{!`¾ÙS–°-+ñSt…%ydX‰ÍÍH•¿ÖþCYYÆ•ò9ú{/P¬M+Mç+õ'‘#„¶"1ÛK'z|¢ûø—¨þî?ù~çûGµûá'Ë *‘W×Bߢ;“J$ïx6«‹Þž<áî®þŠŽ°n¹…%7×MOœòaÚ!j8©©À‚ÅâB!–¢½çÐ¥LÓÌg²éšÇ¢‰§»ŽÄZ[%ˆÂI+ ?@Ìf0 Ï|)ò¾g¹ÓÄø”Zy ÉÏßf·V%Ò=º” ¹§3g¦¯±‚‰â’ž ùýY­t +á €Y@¯¼fê7ûŠ%vm®þdKTÄoƒ®Òg 1œ¯Ó?Ã艞zÖtmŠ¥|¥û&rl(.+þËËXøàsœêŠéq‚uÆž¿@ývÁ;í®Æ‘ Ê´XxìÓª%:­sË“ößÄÔ¡C/q‹.ŒÌ+7•—&‡äëw2¸(“Zû˜‡C1¥}š©ÎýcZf0JX4Ù*sÙèé°8ÌØ=.h»vô›|ÞÆ+Wg&~`ÛEÌJ[Zç~ÌŸÏÎ;G¿z쎄±æ¡Df+êÏR/™µ:yz¢"s‘ÏÒ)ÐDBb¢* _jÇZ³­›m׳ê¾+Â6> Š[h¯z¥X®þ4e󋉖’õÁÞxá~×^õJÑÑ” üå–öÝÄ ^ÐÃ¥ïŠ÷Y{ªy:bôæÐ¼?CJÖˆÆí8lÚ'yQ»ôΓÁû7"µ¤0)ú©’eMù{£9Û}ŸŒ%DIúLÓFÅøòß™4’Cc¤Œü^Q„¿oÏ6!{t®„ÛÀˆÒ[úµÿiV¦~'òW¹v˜ÝUL~©V#K©N–hŽL”C›oký#ækHñç©\#¢ê,67„;½KÈdú¢û”Æ!)¸ÅÍÞíûëx®ÒO4…¶Ul¾WAçj”#d¡óåZ³k÷u% @³dx¼ ^Ô©dë×õž¿ ‰ndñû ôý™(äa͹îöWÞš+G@¶ÑÂú.Œ›\>ÿB*icìVâpÝ”VÈí7‰k„´õ’Vn}³úÚŽÁÞß»À1ÿ4c^¿4Í%¸®pÐÚ2N…ÿÌš#LDß¼Û«CÙv=·:)QyÀ0;Û˜ï)bn#±dIº¾Èv‚Íæ­cV‡wËn¿ÁV<„W"f4ì)¾´mS4ÚK§ôÐ9a“×WéÓzÛ€2+øž|Þâµü ¹°á0[öŽh%`¶{÷ ‘Áw§|Í…þéô#%Û«–f%>fZ5-“—ñʰy€Ðºæ¥»w{û¸…ø˜ºÓr’4±,#nl?ØæMNOžj'%èB¢b×LݬR!²<Á÷yq²€+q™€Ê1$À\ø "GyÁ¤»ËB–ß‹álæ+R>bAWÁ<¹a]°Ìï–•™1§Vë(¦°pˆêÏYo¯U($1WÖ(Kýâ´E?ÞûÔª+=xVüN®#)ÎO3u@cÃéÁ+‚!§EÇ2»uxê{§ëGWC8.ð@ŸUÖ&ÿÃEn­†€¯0?§‡Ε?G§Ÿ,œòˆúžÓÚêÆhtOihrN¾÷Ö2fÊ2¡®`à@MP¯Ü#ë!eG„B”Gæ'#¼ú“A¬'ÎȦ¸ôøûûÖ©'ÏèÞ‘t{|7X u³K=ÍdÔ›»ÇpgtYΞè b¾d7I‡}Í¢*3ÊHúœvÆü£Y*9¬o³Ÿ è²›a%T¬#Ë«ç„ðÐGj„ªH`K«Ÿ ,ûµf5?ÈùÌÔ>aöÝ×Ü(&=¡¤òý ½öÉk”ý…YÈåïÀªÖå{õ˜ ÀS¯9Þ¬¼FF1j }‡ƒov• f¦Õí´¦ÜO˜ˆës.‘GÁJs_ÍrßÔšñcŃWJò«?G¹Ú Ýv;ûfË’$qyXw¶ÍDCû&¬Oðk~QÎÙ[™m\ȧ¥ò(§¥_{MñÝœçH§Â^ï_kâÎ#pè®” —.E´‹†"#ÙDžœŒ}ÝßÖi±üü5`>íÛ £ýÂØG–3‡ËÏI*Áד!·×ã-Ô}!/ †¬ß+è%²álWÒEpø´îÔ<´ÅOL ¾eѵ ^e>béÞ-x…šø^Î*bØç"EdžÕôÌv­juiõþˆ¹ÝÑ0å®1}«8nLó@—ñ>+ &µªF¬ùOàú|¼ð¹6lf„ù±h8À]ÊÅÇ<»S^ñ’¿–ES!~¯.J©i™À¿ÊiHëÆ+;èB›¶PúY¹€Ü*ÁNÈ!]ËÞGm„GkËv7Ìï@éÖš)ñÂ'7XMR”±ßN㻃¸¬ó‡8ÂÊ–ü»Å¶¹Æ»±äË–ÜcÅZjÚ ¤…ÞJtŠovõÝðšGÃ`$ó‰ ²®Š‡MK ‘?НTÜÇàb‚±Ò™ßÀ7ÑZSy(BÀظ²œMùA´Çn}â~oëæ9VøN¾«ØP 5rø Ç*—^´Q8þÿÿÿ'0±AœÀ¶FkÀÿähåñendstream endobj 366 0 obj << /Type /Font /Subtype /Type1 /Encoding 480 0 R /FirstChar 40 /LastChar 121 /Widths 481 0 R /BaseFont /BRXCKT+CMTT9 /FontDescriptor 364 0 R >> endobj 364 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /BRXCKT+CMTT9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-6 -233 542 698] /Flags 4 /CharSet (/parenleft/parenright/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/greater/A/C/D/E/G/H/I/L/M/N/O/Q/R/S/T/U/V/W/X/Y/Z/a/b/c/d/e/f/g/h/i/l/m/n/o/p/q/r/s/t/u/v/y) /FontFile 365 0 R >> endobj 481 0 obj [525 525 0 0 525 525 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 0 525 0 0 525 0 525 525 525 0 525 525 525 0 0 525 525 525 525 0 525 525 525 525 525 525 525 525 525 525 0 0 0 0 0 0 525 525 525 525 525 525 525 525 525 0 0 525 525 525 525 525 525 525 525 525 525 525 0 0 525 ] endobj 480 0 obj << /Type /Encoding /Differences [ 0 /.notdef 40/parenleft/parenright 42/.notdef 44/comma/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less 61/.notdef 62/greater 63/.notdef 65/A 66/.notdef 67/C/D/E 70/.notdef 71/G/H/I 74/.notdef 76/L/M/N/O 80/.notdef 81/Q/R/S/T/U/V/W/X/Y/Z 91/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 108/l/m/n/o/p/q/r/s/t/u/v 119/.notdef 121/y 122/.notdef] >> endobj 319 0 obj << /Length1 1171 /Length2 7454 /Length3 532 /Length 8205 /Filter /FlateDecode >> stream xÚí“U\›ë¶îq .Å%‡B°¢¥ÅÝ !@ÁÝ¥xq-Å­Hq‡Šw((Å)‡9×Þkö¬}yÎÕù$ß¼ãÏó1ÂÌ ¡Í%iá`•s€»pñróŠ¥Uuyy€¼Ü< Ôüñáñ'ú\P”WÀ ”vpôDÀ¬¬]€lÒì% %í¡ ª‚]¬¡ö5 `; ¶uñäJÚÙµþºá Ô‚:CnP n//ÐqšC­`pè/OŠpK Ð¿Â®Žÿ}äE8?š²ým“øhÒÂnç ´€Z@jjÐG/ÿ7lýgq9W;;5°ý_åÿîÔÿ8ÛÃì<ÿ+ÃÁÞÑÕŠª:X@ðÿLÕ‡þËœ*ÔæjÿŸ§Š.`;Dnerñ póü+s–ƒy@-4`.k %ØÎúw ·øO'ýûÛHKGCRCó¿Fû÷¡wÑñt„yþÉþ›yÿáÇ&!`À7<]æ}L|üþ÷“ñˆÉÂ!0¸ï¹ Œ@€=KôHÏÞ¼@Üê„z<:qÃ\¯;ã ´t@þšëãèA–Çþ…|û7ò AŽP wùwLà9díéh …ÿ;$( ÉüC"@ì¿I豄ê?ô˜©öoæ‚4þ!~ Hûßô¸3 ð?ôXòKžÇ‹àãK@ÿÀ¿^âx4ü>ú‡ý:¶à£A»?ðQ×þ|"þ>ê:üºŽà£.â|Ôuþ —?ðцëcxòø…<ÿÆÿ¹iRRÞ\¼‚ü@.¾ç<É EE|ÿ·Lˆ+ñ8Ä¿ÿÎ ûßl {Üq(Ô ÌÏ8@ÄBlRÂJýdóÇÊÐÙiÒ‹C¾u„Ö¥‹qï-‹O!Gu t'D¡D6°r”_Ê Ëç+” ’>}ÞÚ Ð9¢>žá@ÉI;RÄ$À^”D©1†××–çBRP›c×Åzf<1ºú¿±U ‰uó¤Õmø×¼"¯ºçãP|³aÚ‡:‡¾uõ¸yc»/¢Ñ?àÞ•þ–¨XmªP6¦£¶ÝY¼IÀì“*öp.3µØ"Â~:9§C¹ë1_I;r‡¼å¬#AQŽú f()ÁTDGcoDd³ùÍD3S¦†À73èæÀߥ¯ÁE¿ûÑ~uØTkHÅ0<4&ôqH¶Ë£¸ð"ÆçùYòYülµˆ†‡ÆHº>QŸð=ù4šµ {8Ë!iboßûnMì‹h:»zTÀ—û)ü¸·õ7£ˆß¥,ºâ°ßZ&¥"ņC9–IÉ’o³,Õ»—(ˆÝ%C)œùU×éÞG•Fž©£ÚäÇšl"Z˜È»&6ž×*nÍOhŽ@ð# ín?Éš6ÞÇ[-‹pg§Ø‡>8_æD?ì úRáÞG~„s~>ø6ëT¦ûãa.‚25ßÖÖ@wQf’N?´“b›¦ ™tT‡!ûæ|¥J7 %[ê9oš€/wu0žKÌ®èÛNiR7¾î× $Ps„ eOžp:eÔ]!k;OÈmd¨¿ó´ -{ 6Kv0R üŽßF³Ý½ ÞÒ¤ÿ‰¶<»KÍÏô… ~ª3nHAe±(iK£ýíXäyx<{•ÒŒa•ÿ <[¬@ËÔȿΗ!º6TâvaY*qä÷FË4Pß’ º¡ÌõH0ârgÊÒ4¡\Ù×ëE¹Í/œ±—Ÿvdv6lïü®7HR0U˜þî³}Pê\Óàüç²ü·:á©Ïd‘Ñ”F—àL4ϸŽ,Àj?û¬º5L¼T½à?g½Ë¥»½ÜLzwùFÝ»‹Q΢]ë)¡'7ooKeV:U_·›“ñÇp«²SN½%F?ã©uÚ±øb‡p ã¦>Ãj^‰BÄÁ¦cQÍ ½…L=ç]©ÑÏ¢P×Èö ßß&Y¬¸žø-™~es>")|ÜÞL0ã3‘2‰š÷&zó/ô jTä>wdçõ>±LØ*<‰k†¦2öì{HÕH5k¼å±*bä?¢ä€rR¦ØW͵ô›5fÓ™IÌ–ðGÔ1Rï{~w×±¬µoˆÓÒŇONÜZ~>mɰp2NÓº¬Ê Œ–Æ¥òŠG÷Ü—Xî_ìÇ’ð˜öÒ„küðÙß ›Å«ÅfyiPH”Å”ƒ~K½ËK«b›gîkú¦¿vÕçtׄGÄÙ¯˜[f ZµŠÿlFªŸKˆ¢íµ®@”çÅ`™¢šaÃtI?‘¿Ç]ZSÖéoÁ˜’Ma4pħ-R¥­¾m'|{|bnEˆ4°ÏaRªG‹äàÔ5.×}ÕúÆ’ÝÏì‡ûˆ%5–båD°Å"ý? pøGÚÀýÝseA¦.zvHŸ€;^ÖS ßt ¢ûÛ6 ÊS´ Iì#¦vÐèÕ·²µ „q»MOîi”fík¹°çÒʦÞä!Q¢ØÉ\K4>ïøZ?Åšb‹ÊµwDGMéXQ‡,œ™š7ÔàLr ¨6´“nÛIDxŠ-éΠázìFg ¬t•ôµÒfúÏi+‹ãgÅm#½Æh3\X|_0©ù ÑvÔ¯ŽqxM‹:NxVÚ¬Ûüó‡·Zé¢\‘`’ìHW¨g¡Áwô…7£ ¹º7vÊ›•7#>Ô}+ªR–UùDð»x?+c0HÍø¾xÀ\ç¶§6îÇ=‰ÿÌe¶-x_Ú7t¶Æ¿Ml„Dò\}õ²a•=ñˆžÖ‡¿•ma îD"Çá·äì­Äò7¹dÕЧX€º>Qb“ ¯™!«?™4$r>™Ô³i™×oY&àjÞõ XûÌv9#‚˜JîOž㾠$ÆÊ.´[ÀŽ븢~Õ†9¾¿bŽÝwþíì²^‘4$oo¶™«FÔÌUºs®'ÝžÿbòsL£= ãAŸ!¸-:’ K¾E$Ô‚®Xs×%"NBÿY¢»h•Ôbér³ñM°ÎðËØµѬ° 7“(«CP§Üa.VÄS¾¹¾g”‹¶ˆÞ&ž¯9mÿÖÄ™-þvh‚.TQµàìòÚñòE=)¬[ƒÙëùº¸y­úÍ@›põ/Â3íâè´Á{gÀG²¨$ZÔ•wSŽæw#q 3†¡¡ÈbSƒY Ž™Œû4E•¬]ÈÍÜG\æÖp…#'e ƒl©Mªâ>Òœk X|.Úâ­Áwqw–‚ {WFÌÛ-§iñWdÜÕÏE}p1=—ÔW%±3ø.7‚ä{é°(Ä%%¢u¼¿ù‹L5ó ™»ëäD“¨Ÿ=;OPðŽl—áŽ"JîÝ@>}‰ã;’3&ãšœ®:j)³ü;v9¿&Wwšíw,:¤Y¾s='’‡‰ÆYÝÒgÒáoÔ š<MMÄUrW¾{“¸Ý#I0?w J¢Lš7µ“˜ñwUzéGõ2ez){çöáµÞäú÷EŒàYÙÚ{™g^q ¦+½kÐOˆè=ûÜ}¾5kr)*wà+ÝgQmÙz"¼ÛñSy«Rj­]"BLO›FÌ\–‚x§Ô@ºSu4ŽÆ^Ÿ>äWŸ¬4X ¶V' ½_$NŒb ŒkõÛŸ‘¯©×wžh ¯î6*œ”ïîL+òy“Úb¸¹Bï5’ë&Tý¼u¢r?~EÓg`ßf¦òdŽ+|ùž#µ/ÓþÅÌÕ"ïÓ½§¯f(Þx±Á4P>4äÔèOéíµá‡n4e’£urõœaßEвhÜ`|JÒ³Ü~E¬Ü2(+ÅTŸÈt¥ýȧíÚåT©»¸¿U²ØÕn¡NÌ‘y%µ~¸!3‹Š]ÙzSšoŠÜ>{9_ûÌrRaI„ÁÇþœ|Ïz§·A­¶¼éjÀIöÓõk6 ç‚îÕQK.kÇÉ ;’ÀW+x?~^&Z\~lœ'ìXsaþÐGÑMâ¢uÏs¡ªŠ×„®:šH­d ò°‹¯Ì(3ýPq_ÿÜúªØ+©ùó ´~Çùö&qi²*N$¾æ5´Ý/Û¤õVŸÀ¼FuÃ0ð#Úg‚±ú°f¹MNÞn\š2FÅBï¼ %}[ÈãÞOtŒZŸ‹Éýj™ò¶&“šÌ€«7¯TIuËÿîõ/6Ÿo­y ÏQ4ý}¤(q,D'·‰”íl×¢s.¨ªÀ|âßnó[Þ7-¸ž>jŸîŽtFÙxP6Ž¢±IkP—y~‡ìQÙiBµ•祭Àì$Bœ§» ÝWy¸QÙ(ïꎪхL^’S7EîœÕ„gï}Ìf¡êY…ÏNIh«£Jàÿ‚ƇjÆíÑ݇ÓoÅIÔ“@éE÷­j#RÃ7‰Òé–Øû0yÍnMË\ÝzÌ“œïÎûÓ5«‡˜© ®Âò¦ìO#wUò¹ÅhÅ—³SóÌú¾ë$n2m«§Ï2‰hâ{ "ê§.‹­ÂbýI›ÜO؇ÊýϦ Â¥Œæ6¦"^ïf|µåŠº¡ïÆóméBíE³d˜W‘…Üm”@¨ÕšzíB¼Í;µ~áQÒ«d긾iž‘øhB&x>ä; c¼y“7Y±—Éfd3NìÛF¨2e†ê!ºnÚĦÿ»cZ[FÔé”——ŽëdŸç ä[½r~óùµ»á°é¤ÌÉn•F>¤WèÕê×@MDyðÜtMuÕÄZtöPÈeþa¨ùµOÃ’ä Å‹.xSqë·Óì—\DíÌWi—™ “K2Þ®A›±&žLÎfö¿N´ÆBÚE _“êtcé5ÜAÉrŸgÑXp”*Nn†¿ézPz†ZÃ=g1fF©r¥{Vº xí½êÈéÚyеªþ©›‰ ï3“IòL!×·ü¹K½FËÁè® FømR9Ë‚Q}¿f9‰$מ¡U`ÎûŸ¥à l… Ð¹×CUC6nN¢öו(¶JÖYëûa”˜‰“^ù›jnؤÏL¨Ä&<¶¿5~’»ü6™üÚ¯¯aÅë)ia ~EÔá)u<`ã¾nUÞò~fæŠ y(ª{6[·h)uq"†%©ã\}¢‰Ì¬b~7äw^Êš[Ò¿B5¤"à•Û„_ÓÄÕ¡™ÔÀ~dmì"þ‹½YïÍCZ¦®MàX[±H1³RÍëì.NMv5Æà*™‡ÜVÙͪު·µÈ»5K –ó+ý_Vè1ƒ5Òò'ÝÜK÷~öf×¢ÊLŒxa´O^Œ37?[Ýžâ•U`ûéj»¶PwY쿾¦ŒÎÏ'ˆ(Ï {ÇácÊSè=s¤ “çKŸ¸_Rx@úïXïäÛƒLmOK‘Ì1f¼YH£z£Y=•ƒ:Ç»Ûc?cÛȈ$›†Ô]_jp„­Ùú#Wáv }F£Ébj¸o˜õ¢ã´–áãgrv´õM¾më›ÓåWD¡ÆÓE»g0”ßÌ /F«¬wèìÀ!÷$¶OPÌô—Ù•FÁÒ{Æ,<_¿ïRÑ%Í©9ÄÅÔä«5óGNú¥Ø^3âxšƒ l°úíE—.½ñ"åÔîċ׮=;N8°ÄFºF¡&p-ä<7Söó,+¢±šÑ#õúõ]šóÐÓ£wž³¹ jŠþ¯l¨m­Rlha·aù½5GŠUyjÓàÌq’¾ë Œ¬?¹Í˜N߆'j†/Ï0æŸB"bqS\ø3¼¢Ù›V­ã)_ÂËøöÚ=¯ŠP1ñùóSÎdq7z”>›©RÊïjëÙ>b^èJ»cnhæ[6~x!¨MXæà£Y”m nÑ0FÈ»ŽËºë?m*D}ºQqmýžîLøC’åôPAP逎DñÀ­Dʨ9C“z*­?$“A¢¤QÏâoël¥‡WÓv!{d “01œ)-M™”ów> qs#‚%X%´×ŒåXr&L/-ý]«#ûþ2 u|’doHmc°œÂ`rBà”>Ŧ Sß”@¨'D›4…–ãe»?¡Ï\IÈÃÏZÎz¬c8_aO<4ò²HÄùÁÃH' ¡lNÚ=$›Z–I'Ç_äûÜÔ­¨ oŽ26^ s®Í‰Ì 6“û¹µUÜÑŽnI%÷|ŠaÂ=‹s¤š:®šVäs¤ä Ñ¡í(Óh/º8ÇÁRrÕ)Ïhê„y}%tœÂLuíÆdÌÍÌõ}Òг¼Êóc¸¤÷U´%9rýœê#È?3®(ô‡°<”ˆ6ͺ4塚Å0YyŽ’>’ÿg*ÕHbP÷kÊ(iPVEP0A”k¢cÞkÆÌw¾þÀ&@¼«,/1:¤çðýZ#n×ó£Â%¬;°yÁcàJ¦}ʦ->OßI¦Ð§Oÿˆ8§H6:ãO',†È8õòåPidw?¸nï8…t´èÁ¨ ËnïË\u÷“ËËoÄ<òóèÙ1¤T2Ô<¹Æcò²~ô´+­wM›¾¦Ñc¡Å¥ï_ùŠ}žž>ãzi“GÐ4Üî}‹ª5ëƒ+ÞC#;wÂ|+P–Šz²‰k~zduÇ@%ÿ<ƒŒ}#Jë)ŠM²5 BŠA [ÜpÿäÆÄÚýEéÚ[üc"+Càèsª>ÆP :]œ:G€¡/Áý¦æ[ˆôzk9=Nà†øg =šÔÅ£UýÓZgçŸ-Ôk q»Üc®B3]ž´½›j֜Ñ™S&Áê‡6¥Jã/ÃmýÊF'K½\¿æ:ÿˆë±ÔK‹”M^¼^›—1êé7ý¼áˆh÷›I{Ê’Y—ÒSœèƒÍÖ‘ØçˆGN¿©*>)šÉ_±6y)X9qŠq£.. ø¬³¹ì펹¼O¹¤ è6¡=¸!š8ÌÚ}A°•) £~‰L›)e6QÊvêÌ–W„uØ$þ.“._#ÞM–>¤B¹íô.s7ðªªIìÝ~ŸyNDFAÃS*Òí3¢ŽIÇ^buмUvdgeÙäÁ»ùº $Ž^5öЦþù0̦‚þM)—¡ÑQÅ4›üw:ƒ-ò¨*ÍÊŠ°€¡ä›†C]êÈ«µ„Øåéú#Åâ¿CÍwßñsí¶‡#‡”2¼ÌÇxÈÜòýÏÆJî$EEr«S¸~QW•_v¯ë½­kÊLpÝ0$àr4§j|¥¨JÜk3«ÿ9Qs­‡É¬èˆLÒ)PÞx챜p9VhG4Ùq··T ü—÷Iº2ƒ?½z]öþõ8(¤ûW‚MïGd’Ú¢"­6T’‘SʧAº Ý<¡™¨XÔÈm‹ª )aû9Ó£¦i]ûp8™‘¾„kYî™DÖLî PᮉrƒÁ\œ{iÇ&ß6áÐüZ#_éH•`P9üéàþá0ϲEEÌÎYpÇKZ,:àÚ²&ò“ë°É˜Ä ²uðB›ÈN:y5 }i’ƒíÉ~:€áfÓ¹Ï>iõ-ÒZOxÎlÑ»ØIÞ(ÿ™dÍgJnd²žhÐq€RW—Ž2¾öq­Ã͵|¦¯¼&ì³î¿[Ä« Ö¾oW.‰m•^V›ÐŸŸØQçš-:Šõ„ûr¹º?- ÓÝk£†C1AKtÀFŒïE2Ù<²…ÌýŠ ¿R;•¤õëš§øÒ3Ü3»d “?ù;öŸ¤ö¥ßÈŽÐý”ƒeZ>!¬Po¡ /£gÇjÓ“WBŠ/úb&£t€´èŠT¿Ajø¡¥JwÂAŠcÛÄÐöû†þ‚ô0e ÈJ—u.<—9Ë{=®P»›rÏg ò½0Zíá©¶ÅùÆÃ9|ZÞéTº ‰Fnã~aÆzþ™º–XíÈlx Yã’tÙ ÿŸdÇ"âü El&æWÙ‹YyÑsNÃÊ8Ç;øzvS§ª–a61Ö|†‚_ðå¬\€³…Â/î›Ô«ƒSm´Ø8”2'!ñR*—»5:V*N‡þÍ'•ç;¯Rksã¥ö²ñ2 ºû˜YˆWŽ.ÛdMÆO Ÿ©í–ƒŸ.+WVwð§Ñ ÁÐêæj܈e™+Ó½ÀA;ú[ûý‚SégUoCƒCYl ™[âÖ×çfzG§§™Ü­™i, ¸>|Ò` æ—¯),’? ãÒmáúôæx1*ÞÔÓŸmêÝwÕùkð^„öZM¡c¥ %Œ®n²¶'$"ÍŒñj­kÂà‘^ùd^áyÄÞÏÆ‹ÜZ¢"JŽë둺Ýßmî>E8¤¾±ûýR$¾á6;JL£€»·ü›v º·(ñ9H¨ËïäòþVgÓ?2å8NÎàU¸m›²¹Ÿ›r§JKèUñà}Ø..z¬ ¡üp=‚¨eöbpñ9£ë¢üÛÛñï’ý߬(ƒ}fÜÖ ]ZöÝ=™Jv—eŽƒ¾ÏωÝ$zœ^1üÎ;V©Ð*k+Ñìét#{nkç3òÚØ¯„»¦«Üt6s}/ŒÔ³logÍysãN¯¤—Ásÿ¼?fz‹ï˓ҙ,s þj+øæ÷œîd}†½OƒpJöû½jdÿlÙT‹Búhu3yÂT‘@×}Ù [Y†J¨Ñü$뮂¦ò6¯ã¡ô)˜M}.cd¾Ãü‡„úÀ³‚[u¤¼ç›ŠVze÷¾O¨KKa>J!fý£VWs>¿ @d݇å¾Âa“$Ö*ã¢O]ͨ ØJ#¨vqòšã>]«b53@¾Ä€¸®Uш_å›ì¸î“ƒEðõ•ð¨[šÁ¬æ»+Q 7º) ÉÎd`´ Švž~d§Â1¼-’ˆ:†€†ú—ôdÏêŽwÒ.øÜU²W9ß© +è7Õ1ôz·Q7ñ)rBl1tçªÌÉ~þôZü8l._Ô'þâwñôXO^cÜüec«L *ÿ°­]‹µRk_ì-´gçàú&)Ÿde›—~æq€_ÓáqñC8‚é‚[‹taÚ+‹²¶š¤Äéj•ƒ÷y—¯2?{â€Y“4)AQ’€WVL›%~fgêZÔG4k³ßáX"1e0eþü1£a€œˆZn9È@¾ãÊ¿ÒÏÁ6-» åˆça‚Ó×>d6.µuràù?üþÿ' @ì `„‹ƒ=a ø_"Ÿ`endstream endobj 320 0 obj << /Type /Font /Subtype /Type1 /Encoding 482 0 R /FirstChar 11 /LastChar 121 /Widths 483 0 R /BaseFont /RTPAPN+CMTI10 /FontDescriptor 318 0 R >> endobj 318 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /RTPAPN+CMTI10 /ItalicAngle -14.04 /StemV 68 /XHeight 431 /FontBBox [-163 -250 1146 969] /Flags 4 /CharSet (/ff/fi/percent/hyphen/D/E/M/N/P/S/a/c/d/e/f/h/i/k/l/m/n/o/p/r/s/t/u/x/y) /FontFile 319 0 R >> endobj 483 0 obj [613 562 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 818 0 0 0 0 0 0 0 358 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 755 678 0 0 0 0 0 0 0 897 743 0 678 0 0 562 0 0 0 0 0 0 0 0 0 0 0 0 0 511 0 460 511 460 307 0 511 307 0 460 256 818 562 511 511 0 422 409 332 537 0 0 464 486 ] endobj 482 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff/fi 13/.notdef 37/percent 38/.notdef 45/hyphen 46/.notdef 68/D/E 70/.notdef 77/M/N 79/.notdef 80/P 81/.notdef 83/S 84/.notdef 97/a 98/.notdef 99/c/d/e/f 103/.notdef 104/h/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 120/x/y 122/.notdef] >> endobj 304 0 obj << /Length1 751 /Length2 1206 /Length3 532 /Length 1758 /Filter /FlateDecode >> stream xÚíR}ÙݢÁÅ‚ ' Ó(4àèêih*I_߇Ø"C™ldhÖÖ4ÀS* Ñm̬mÌ pÄQ8"Û·/“,ƒá0‡W¶(â6¼0 ‰¢(€ Àsù„xBB—@\ ‰F\˜#AP0Œ’L–ý¸ < X~,sÅ‚O- „ S`ar; ,r1‰\ˆG2qÈ» ÂÉïajµ¸“AÜØüey"£_uÙ|‰úWã Ä"®ÂÑÕT_è£5Wˆ ‹ù«»."6sh0êÇ,t‚#!®;,â„B+uå®6AĶbÁ„y`ï~·½†+¯¹ÒrgèÈ;JðoÑeî ¦ýÙàp$ð£R¨TA$¾O;ÿUWíF9F‰q° 6޳£HÄ\ÈÄÐŒr¡HE~M((&"Ž"’8ÀÃpÒòcš[ …–‹+Ø‚ LDØ þõ?98`‘1Æft`lJiTK*°´ Æý‘#Æq­Œ ‘Ì'̃‰!(â?Ä8¶‰¡¹µ'Êãw—ôT(ìuþ!ÃíjëƒæõÒoe‘²;ûÂwŒT³*ó7nW×XüB˜ÚëÑåôòXxF^ÿ‡qIàx~tý¬Ù|ר1Þ[é •ÆÚ¾ù) Ù½#åÙ‡JÛ _ÝzQì¾éýwÅ'd™ë~’šë‰tK–S>r0éxµÙS5/¼<Ùi¡È=òɉÞT»qH¥-à»åNç‘çU®‹e-Í´­•­³>êáOZ|4”zUÃŒ¦êµå³´sßá._míÀœõê£îÙ©G'?6S™™ÐPº¶îmå.«@Sû^ä3[yíäÛ©dˆBbòTwÙmmÌUßáRçpý«Ñ^Ö}'É=¾‘ÆA´MÒõ%§×\mŸ–u´Uœnk~Ò³4í7õØ9W¿bU §ñ;Jæ<ÕN7äìü9 õ¾NÝ•d’ÆèöÃEµ <ËÿO $onf榺GN¨Èê¥ýŒƒßMÁLú/u|o8·o¡Šþ²ˆ¾Vè‰eìåäzè÷â ö’qÕ¥wtêç-ž|–’°½ÔP°ðí–Ž:XáµÍ‡ƒ/Öß$HÕ“²êînûæé“n5÷_|;7ȉ´•ÉœÎV¶<çEiw[WŸ¸XZG)Nhzm`óóJ|ëdÆfÅh…³‚³TÇÄ΀ γ ªò£û&¢4›$mcXàÍ=±<Ó–V¹ß§iý1”ªepãò¬8Œ.ÔŠ0*›]j[\4ˆ‘×Á4¤µ—KÛÞ\u˜VpI•jÏK'š»gä/­’«Ï?˪¸÷¸¬¹#=¸Ùa?$wWóøÛ :lj0…Ya ªµPÙà˜S_ªþY+¨Òè§ó;ªEÃ^ÒÊKL½wvY¦q>2jíÐèYÊ”|ÙLCa`@³ží¡®ožËœ¿c™1QÓˆ¼¹œU›4÷`’±ù’Š\[ô_ ¥Ékö¥—L®Iî)ž*š¿õ“£ëF¿\gê¹Þ¬p¾âýˆýd±²¬—]ìm½JMöE½S^±ó‘%Çî„;•5 é˜=u=4raDYKr)†™¦qB{(EƒÇ)ÀÖþ¥ÛÖg11± DüÓ>Y¦“âØ&/{ßû.z¤z0“uDL8éŒùßÍœÎòa) ü­&†”|Ø?„'5ŒÒmÖðŠN¿Ôî)rç KáøØ‹÷:­é5ûþ±‡Ê’¡hÿ¡Ò9}r©7 ®OÖ>[¼µ¸ëmÁM½ ”p™+-ãšåÛÖ6¾U×KPßÓ—kj¿4R_’H;¦¼vWÏÜ«¸ô¦“Ú§ ßUðvl¿<ó3Ò–¿5 3ï>KØÚ±!¿ø£Î?ô•Ö¹™k¶’5*Veº[.‚©–JÚ€Ëöþ[çp•ÆÔ߸HÿøŸà a|6Fú'¶‰©6endstream endobj 305 0 obj << /Type /Font /Subtype /Type1 /Encoding 484 0 R /FirstChar 49 /LastChar 50 /Widths 485 0 R /BaseFont /DOJLNJ+CMR8 /FontDescriptor 303 0 R >> endobj 303 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /DOJLNJ+CMR8 /ItalicAngle 0 /StemV 76 /XHeight 431 /FontBBox [-36 -250 1070 750] /Flags 4 /CharSet (/one/two) /FontFile 304 0 R >> endobj 485 0 obj [531 531 ] endobj 484 0 obj << /Type /Encoding /Differences [ 0 /.notdef 49/one/two 51/.notdef] >> endobj 234 0 obj << /Length1 1916 /Length2 14234 /Length3 532 /Length 15300 /Filter /FlateDecode >> stream xÚí¶eTÜ϶ »;@ãî܃»»4;ÁÝÝ  Ü-¸k°àÁ]‚ûôÿܹ'¹g>¾ï§Y¬^ýìªÞû©]õ+šŠLYIÔd ”9¸2±1³}ˆ+¨²±ؘYYŨ¨Ä&®Ö  Wà;@ h ~þûÀÅù‹‰ rôr¶¶´rЊÓý3‰ jt¶63q(˜¸ZíÁ9ÌLìj 3k «3@ÔΠúÏ'\ª@ ³;М‰ `nmæ 0ZZ; ±ü£$ã`ðüWØÜÍñ¿‡ÜÎ.`)í¿4é`IsƒÀhÄ¢W‚]þÿÐúÏäRnvvŠ&öÿ¤ÿ§Qÿǰ‰½µ×ÿž²wts:@æ@g‡ÿœªü/7 ¹µ›ýŽÊ¸šØY›‰:XÚ¬ÿ²v‘²öš+[»šY,Lì\€ÿŠÌÿSܹ)°ˆ«‹)¨Š1üמþkLÙÄÚÁUÝËñßYÿ™ü/fûÃàî8[{ôXÁíeOÿþ÷;ƒÿ¨%é`2·v°°sqLœM¼À§L\6€µƒ9Ðô ³0;€\Á€{â°9#ý³¡à=g±øW쿌֌vóŸÉ†9x,Ž@g3 ƒëŸ€ÅÉ nû¿ºûßaNVðTg ƒÐâ¯(ÛÿŽþÇdpYG;7—?pa3½½ÉŸ€ÅÊËÑ èð'Äý/kùŸXÐÅÎÄÅêO„Àâ tý €}AÀ3XÔÕãÏ8XÑÕÊø×Œzrsþø§KÖîÍ뺀÷ïß –uºÿå Þ+àÿX3XÕÁúoÞÖlúó!n° ÐÉÍäφpƒ‹þ!pR±?N(þ‡ÀÙ$þxÑ’ÿ&ð’¥þxyÿxm2\OîëÉÿ!p=…?®§ø‡Àõ”þM¼àzʼ*•?®®ú‡ÀÕÕþ¸­êì¢ñ‡À.šì¢õ‡À.Úì¢óoâW7u61³ºþ“ÉÇñïøÿ<›àKŒåÏ1ä§6ýCàÔfžVð:Íÿ¶ï/üçý…à‚–!x­V!x±=–¬` Û¿lñ×SÊ Ö°ÿƒà›‡Åá/k€þB°†ã_Öpú ÁÎá?ù/7Ýõ/[¹ý…`+÷¿låñ×E¶òü ÁV^!ØÊû_øÞ¬bb O&vðƒ ~aý§Í|>n>¿ÿ1ÓÌÍ|­¸þëø‚þo¶°_ç@ 'Ð éçÈŒ?Ä&½)ìë'ÉÂérXzH1ËæÅúï?:‘ƒ—!íJFåœè×ë´+²°Ñö`÷H=ž‰\¢:|U&¤Î2æ_÷Ü÷²¼[‰´g)xí:’ߣ·7Í]ŸpA*Í®}MÑ)Ƚ<.P¦•P߇_%ƒèÑsoèÉáæÑ–ʲÓ­£æ SÅÈpúÁ¾æ‘’³6üÉ&¡…aåÔá†õXˆŸüª‡iÖAÊ¡ºE£º/|RVŽ^ûÖ?\-’ °TsìÁ.#¨ŽÊça‡Uçz¿“4š¹ÀŸ”ŒPp?glíÐ&{¡â6X/Ù1â`0²*’]*f½H*UÆÒ< x¿Òîù¾tÈ%ûSnœû¢'»ÄjêÓéÂ’¡¶ÚPàëdeOãx³¡]çh¼ý„Dî(œòæã&’e êWâ‚d½ñh#F÷üIɽP@ù0?¯‘D^®_ß™…$Näò—Xœsõ¦¾®òUL…çYu(ßn*¬5LŒÙºˆji•Z“è—O;)ž!“\D2¸ÂyHôa(>&aN¬‚{ßàÊÐ%ÑðáÜÝ÷Úè³(+;„jF}¼ù_Ë”NùÆŸìÕõê:úó ñÒÍá+rS4ìæ.(ϵ²­ šV?T‡ Ñ:sÇñ‹¹®ÁrWÇ›Iõ‰9S²ð“1Ê-BÆ:”Êg¥œB$?µ®7Ý0¤«'…-߬0Ñ3xÒv/ápdT6ôÜ`Ø¿°¾6ºéò6î§ÓWôPÀå¿Ë|¾'ÈujY¹NUn;ʹlõíO“‰OŽ~‡Ñäô;¤(ÑY ×ÂñÁAúçB»¿ýÐçGQ’ )‰²Ù{v±3aqõ̾ô³RˆÎ¢f­I]û†d½È>Tlo¦ÏúÝöTœÆÅ‘n·M›µõ J„²ÝföJIºQš¯!‚ªÊ"ónÿH^öDB¤Û¾"sý…Ý”+MßÌÜ‹,(ú·õɰ7qL•gÓ®I |zÃÐ({ƒšˆÛ­ Ñ¡ÎÌ-—”“ežª¿’$ÈCŽþþõjiŸ%:óÝ¥M¢~ ·[š¤p¨`ÂSP¨Tvrà–m#/a±µ„v7f[·»Ã9;ÿ4r<·”À¼ƒäŽß÷­rÌw‚-Σܾy“ Y%!>ÍÚ£3&þ¥ózZ[BÑÏ/Ñ3ö(Ó· V2Ù’PΧpùZý¹9 dÛH=;ßÈNò+v6¿ÖP­£e{òmv±µÆž¼”G\ vŽép° 'ÉöEbcFêøô GŽ8{–ÉÅKÕôõè•m¸”¬wÎ&Êèk:*âå‘R¦mÚY˜¬äÙå³[âÏ3Áî?òÐ×¶Ÿ”:Öl|,à¢2ßÈ/n›.'ŽÑFŽ–0¼‘iŒÇ¥ 1r-M ©QÄ1±b$\½kDg­ô˜í—l»c爱“0'úàÜk;Q$¦¬mG^ØöÎz÷þS„ò;~v¶PZå;4Y%Ùf]×¹Ú&Þ•‚#4é %·*"õ ;YWÖÞ‡òIÔJþÄzŒ~-fØ>¼kJ»ÞÖ˜aht' ¹þGXØÆó¢›<¥/¾B^¨Öa ¦ê‹Û*{Iß(ºž*;¯„¨¸²gköó­, 4£‡]ɯ(ÃÆ”=ì>•ï_v{ÖÑŽ²««À© šYeèÝEãýªpZœd´ù=%Gë5÷CÎ×ó1ûtàË?²«· "j<ÇyÑæ•ˆÃλ%' òƒC(iEC»–eµÈºÞB™ÿ> KÐ\­Ô{c ÓòÙ¶3O™®i(—j[‘߆Fc”64}fœ` óPø :eyÌò «(´ñOv–ö@º¿Õô’·KÜn¹L‡4ëòÛ´hñcvŠqSñݹ„ŒX®hÞú|ÈûÎÈ‘CÅhÓ“´˜›ÝÇkNå;"AZs*‡1å×ÔË;â^&2ª‰í_À§Ãp1Ün™Øù./ÌÈtÊ›‰¨èü¨?è¢äß°ëæi›?¯†WEN…Éc¤³ÓhKs¹*+Ìètò‘9"ŸÖ5kç3œí+–w~y¼u g÷„¥ ž Á.2¬Ë(Zú×”ëÅá{Ö• óò4VÏm=€¾êbsü-*!zP% mô1›^¦ã'÷öötS‰…‚+-òÁ‡º_»±#Ð÷»°{ˆ¢Kµ v7ã+•ׯb<(+¶AñRAËs‹žF‹<[*ζ±¹|!yŠãN,$‘(–v£°î=ïì#ˆj즷!M€ÊGVƒüïuh*‚Ø´N>wr?ˆÍäbRÉT³ ’ƒ5v6ìÆ´ðûõ°ìßœOÃPÒÌ€Ìln»¶Ú¯f‘©7îx IÁ¬l¢óÔR¨}fnä‡Qyd›£ Ç©KµK§í«{NùÃZè/^Äõ¦Kûë ˘ýûZùÂ8w]¹_£A6í¿± ›DjœË¶dc5³à·Ú#¬ÇtÇŠå74í¿l Ô“÷b)‡” é½ã-äWô/ñVt^LVÔŸ!@õ‡2é6Ø@³ŸJ¾WÚDK6 Õfç°»0>ëúL2÷äqͨ<@HÚ¥]Ñš`/Fo¤Y[!µ 7FO =4ôAo¤`Ú~¤òì‹s5þÝÓ!&*ÝJh*:,Y+IP€a™âþî§JëàGŒô’ǯ4•ïžU“ýéºÑ'åŽU4ô…ûxY/œ$ŸõyÈ;ò$¡ŸGøè'ïΜÑNgãÒÏëÊ•è8('ߤ!ûí.ÊÎ üP Zšž1H£%X¼KP;œlYûý]‘ùÚ³m Óu)¼ÃA¤õª‡B6 ïnu‚=è£ lV>¯ö<…lOJÅTG(þëfÓä‰ÂÒö¹¶ïŠ˜›ª`ÿÀ"bbö¹FìÈ?“mº]o>ØêÎ1ýÜ_™þ<‹r‰kfBß”¯š&ܾu¢JKþû1áÏ$]y{ ‹Áêx±ƒÞµdüäKÁ'öÃe… ?_éK.ÓaA¿C*Ý¡Ìg”K0¸ÝñI9ýÈÑm–BMüwïŽjñ1s¯¬»3LŒsmÅwz¦“A²Ì£{±‰Ù¤8Ô…¡P#BŸ¯]ú!×qæ~>!ú™v´ÕÀ n.nf’nÄ jz? &ꪑoE]0püH=“¢(¢<†8²øc[3Ÿúy&ýG´¾=ï~ãZSÎér¹$jfOÁSߪyæøi‰,l§gÜžÄ圃”Ø@ñdÈÒ¢nåôW›·×ŽyœVæAjtZ,"—| iŽ^¯fX3%’Â;H zÒ25‘¨ßÏa2° õ•k·L^]ÏÈ,"ûÅ3'QqË –ΦóÉ]ó›„c®'¤Ñu½æŸã—š>ê–uîÀºÞ3åZ«» Ý0ÉF‘Ñp»Ò]Q‹6¸ðKNâPHY7 Ël5ýˆÃ'… ™ ã…c‚¬µXu^2ŠP7‘áÕT…UûœÛ¢bò„²¾%ý)§þäŸ÷'ÂIP÷51Vä =?qõ“¼®qEÜU![ùS•¨RlãÖ@êÀGÿ]a¹¨¢ ÈZÚ'C._/ÿòâ=Ùæ¹hN ¿ùëHֹʊ®<Ùµ{»ô»Þä Mzø¸Šy² <µ€´îàb ÁÁ¡ªLÛÊï ,aѸñKB³ßƒ‡ßH½ÔÐ '¥Š÷mzº65!Ч“û\…õÇ“”´/ŒýÊOXx™”10ñs]Þ­·ï¹§¶5ïT Øðeåì~öÍ ¸q³Éá”´OÒVvsàj|ìö¡‚{ÏÿÐñ½¡´ÊºýSÛÙûY‹ÖÀCîÃÈ ÇrCxèû2}¦€Xm×åZúv|÷€<(vŽêC¾b/ªñ¦£:šÍÊ ¥-e#Ý_\òµ8rî-Xü öj4¸¡í†ƒÑ_áÖdçí<þÖ^†î°ú*£I#˜Åæ¦qƒÝè=ûß)]` Ñ=êy¹C‰.¡YÉõð…dïM?óxÄÛ¹ ðsˆ-³ë\«)…Îú| –ûY5Î,øâÖ’Wg.çœu°Êc³‰*´nÁE¹ï¸ƒºïýºÇ¶JìG+KŽIü»Fȶ¼ì¹7ÖÊø»føoÕ8®C-íéäJäSV±ŸD®p»ç_f3JÙ;tqâS éj"Iw|ö7ci߇ÛD^sµ»ÚÎüSiO*+4ÆâgÏ&tƒ6€yêo »Mæî$Ý´mN °fÔ[力¤é_8‰CÒyIFÌEòpõu½@ŠuÊ€g¯-˜Ú³wò7D=nïÞñW„ß&cgGWøß·2äZ,s¬jðÞ0‚ºg„ïNßš“í‚ñ[4ƘߋÙrñÒ.ýôS€6‰c–q±øeÑtòðÒyè¾Âì×vÅìõÑtûŠ'›yÛ¨Éâ'œÕ¬ÂÔŒ>^B¼™Aö£öi‚†àš’¾"$;.™äðÁ}›`‡3Û=;{ÕŒ¤Æ_lomådìÝç2ÌKD_«Å°#ä¶wÔÜO _”X‡ñIféÉAåЩõ˜DÏr´^ Œôr„Ù©”áK>LX®ˆëåõ³õv>b~æT$lô”ç3iˆ†¢wY¶rƒ ˜m.»ø íªIÊ«øBôùs‹¨Ø §~‡IþŠ¡Éð¦mxŠØ„ЉUè.ÌyšÄ’¡Ew; ºÝ`15·Äý&¨ÍQˆ næÁ*1°â0\g3°bÞuØæªª8i”Ãò{¶–7MVhʬ7Œøi9» %òþ#ÔgNݼ¤ “?SÛˆ¶tk‡ËŽVSôXð:xñï~…Ƙuúøà’ ø E¹bdšuM~—¾¼]‚È%"ni8F3ÂäÀœ¥Ž’W¹-ui߀ú£½å£í«&O|´žv”Œsô‚¬ƒÎÔdJ´úåÚÔ×h"öÀŠÞFËçcE–FžÓö= ´bê‚6’àôçÈî6Y²w¯Û*uUY¾Šiöù+7„ÖÙ¦âX¯ÄÐpª$RÜe‘Ó°6‘ „K'ä×"–^¶t 4tï22ã´T²’K?Çft߀T†ë0M4ó«sá¥Ëñ╽!û| yÔlcØ1lIF»K`£¨“èL¹V+"Ö»òÒ0Ÿ‰6s¤ÔN~§©7¦ûÚº¿Z*À‘A·¾{ßàCï>ÐìM1ц†‰A§*7üi«OuÇZò>q×QД¾,|Ý—â’>IäBÏ|¯‡Taîe@¨¶®Z`ÙiM–A‹ÍQ¤{cóx¤t€ÚBw£³Àx£ò#gä:P£xÏÍEÑWtùˆ‰;Ô™œü]¦Û<á+,®”à ƒÝµÿ.ND%‰ÒŽX~ß{áV#ŠÑBjÏB ¦ R› ¿ˆ„wž,à”SÒfòÝ‘ 41-P]•çx}RÌâù[üÔ”Æ?Ïàp¨N>¹}LsPD?ÙTv¾×’Šð´Mñr{E[&,§ÍÀË÷¡%Ÿr)ÿóOú“;i4^Gsßù>î¸'ŒGÉ„¼Üfm…(Íf6DVW`8T¾ßylsæa\0ÒÌ8 Ʊ:U7¢Ö>±|¸Ü‡€x ™ äaeÚOïŸløŽ¤Ýµ±=ÚïZ:.g©ºýÜä ¨î„²ä7ô¿H3ù´z*áknȳ«BŠº¡qpž÷gÓï^£FYëÖ¦21ÁPƒØ¿Ä¥Þ-z´ b×X^:ˆÓbA| núNL[¸ÌÕú…Ó ^ÈÐ01 /{8†ÕÍÏÇlÛAZ¹T\.ûƒ³Çcñ \ôÄ(‡{Ω ý) r¾¥ØkôtslÊì‘àˆ”—ÅÍmG¸7fhÌDp³"€dì{´òÌÎqèž ƒíFÀÞ“ýí_}´éÆ}&ó!GΊ-Ú$~€»ÛøèyÃ¥‹£*X íÛR-»é¹í|m2‰Ö¼<§„£ªKÓ+ìÖiþúq¶"ŒÒ{i_Hû¼>Š5ÑÊ +ŽÎaå÷õóâá@U °¥!-(p8øHùÛogXÓlÿD5Ε€ªý¥2v¹™7¼3•c<è«È#”j„ï „'I”¸^¡È¹å­F°ðŽÛÌU\L^ÑOaÁxõëº ©„4dŽ Pô!Õ€D!1èRÚ©Ï`Ï“”Ä”ÝU@íF®õŒxã]Qï绨¯ŸùC9®Ê;Æ^·ÉsŸÀ1™EÞ?uãÑ~»]°›l|Go1@cýAŒŽ´iYHš­#ˆµÊc|áxÚ“O‡Sì:´ú²ÂØñu°ÈÝÝ¿¨ƒäFÈD”Ž¢UÙV‰ $„ÛBO7’]Ç€±^1VU×ǘ m—Û-&Ñ®=Ê•kÛ\ìXM¥ª\8~.C[úƃ›/¡s;F.„ZÎõá\h=L­éª‹—Ïr¹ˆ‹–Š»ªæ"Ó’!Îoº”íçÍw# Á^*‹÷{Á‚ »fÎT!½ƒ…‚¾—ÃR½ÅO#ä^®ùçEpQD㬟&á8ác”û²!ãylÀéM"Më"»2}q<íÁ {yɵ¹¢¨1ÏæË`Ÿ»²¯œ|Šcá×Wи©!0‰ aÝó”ä+HTÖ#½¦À l®”(á&‡HÈ>l°k‚R(*e òµr¡8l1†ïðÌhGãfÓ´O’zXp°}FG.ç?KDþxñÞ†:!,…ãDÄkcQæuûÃ]ßQ!WË¥lXeçjP‘Šnó‘%#ÔñÃfUvÙˆy“b3ÙxxëÇN(*ˆÉÈ‹Ñ1OÉL&®ï¿îëÊI¼| 'pŽvºd70Œ-FÄDö=dLj`4þõ€%â"vÕwŠRl•äⵎ¢ò¯Æ¥9RcŠÑwãD…à=á—`íïn÷­‘n+o«¨Vžc­l5õæ ¨j^¯ _Êla¨“_ÑpfÞÝ–¨÷Óð7&ø‰`¦ÛN¥2ÌB“#~[þB˜®_€ž¢ÁO®?Ô•T[Ze€þIOÍͪSj.—¿„5¯Wùo¶&xøÌìwŠK)·ìÄD ‹CÛ¾C”éP8B×u›ï‘s0|nèÈŽ®²ý_ß'‘ésB2H6Öw8Sf^h’¡Ø‹2æhçÃï¦Ð•Àº¾¾¡4ª,¨}íí75ÜÓŽqWbÛHßnñÄ>M—£c‰‘þþ6ï ¹ºlÐï‰Îxù3£tÌuujܬdzs–sêÄiª,"pR”êü>{VúÙtÛV€XYy¿X‘Hºj„‚Æ[ÿÍt ˆ¥=‡é%†ÌÚɵ½,œ†P…~’༗Ñt©4W¯ªÈóŠÖàh W¹t§ò²Ø†ß&ÒyÖœRª›TµÏÚ1*¤¡]fj³)5ƒSv·. ­ ©Á|9LNñcîAåk_Þ!.§ÿ9g —Ý[ÓÏ™V±7sý N‰ŒùjXRqê€Í]ôùxÙÞóWŒ|€ë©ÏàŠºÂøÛû†ÒÇñÂaÈÜ„F€ V©€õÝXýËýiU_S}Š ±î=òËu çYDïPü´ýdØ•Vó Åœ•ë2 ª`b—9ï|'-÷4”YuŽ-ÂýÐgj‰)‰0Jœ hÉ?¤“-§Álå¼2ã‹°æ€Añ£bÉ%(û ŠShB븎–‘JŸ\aË¡BÁEê«í~›œž„£ŠÚÊÄÙCGúDÞ£z!påÑo^¦ íF;òS«ìÜzC5lC#UÛ¢ò²ýÛܱs¨¨u 1”ÄAEMwb­Ê¬ºŒÙÔêñóÛ¬=Ãp‹ô9;z*Õ÷6쥳†áKAèÈ¢ê+‰ÓÛ4?:@Á|µQ‹†ªZü9OÛ}aƒ¾/|rèkÃ6õÓD§ÉZk"˜:š*ÁÑ;a"ñu?ŒëØD«¨Õº% ÈsúûêÍå}é(Tþ&zî ìÏá\ªw‹ë,Ò dªlK9½±žj&ÒÞý_Ë„Cw3FúßSÈÍÏÀž,OmG£ÅŽ‚ìõöŒÄ„$·½Ö¢çëjo‘ôëPìIÈ’Ÿ.r–ÓQp.Ö´o¬…¹W¾[UHÖú–»!.=l×ó.u e¿3¸Ì‘ ×ëÒžm§ƒ®\-«y¹Ý$cUbB½µP°Qøˆê}ñÕ蚤ÙOôÝb«“%ô7ºVx[“:3•¹òêÑ3ÌyD±™˜ ‘õq]U–DžmsÖ& ôhrÜ0Z€ezTXÏÅxq“¹è~k•åRd"(z;Ó0K³’å=n ÝlIƒts‘pÕ‹Paë?Õ×NWSèÄ;ʇúK¼&ô؆g_}û¢Å(ò¥2ªDiròZÛ‘‰#¼Fpf\'’^\Ù<"û˜Žh"í'Uä¡]ë3]ÓòϵÛW‚íž”Gß Ì̦Øhw÷­Æ¹„­AjmA+E¸ø_ªñÜ_LÆvƒU>Iù76þzålÇÒ¾–r‡é’£ý(ú~A cQ !d'¹õ„œ»“Õ¿ŸÜp1™ÇÒð@îóÜgÁz Ã…®ëYšâ²Ó¯˜ÌkÄ›„èH£ovßS/µÅ£ÕæHMqÊæo°5-?1ÛÆ=t&.â Pý²,üÎ?" ‡{AâÙx3ƒýmô„c˜Ô*¬’©c·H-u`‘[tI¸Kê4ë[ìj 3æ—Ë·Õ.â.4öj bËGÅÃñW¤q·²§lsxdA¾û*¤`ôÚ—0žÞvÊ…E©0í(MÛì¶ïŒ’á—«¤ùíq'h÷ôt¤¤³‰¢7š¥bÕÞÚ¾nºõgî,‚į<.ø›‚LœwÖ°Sœ›m[Èø%eaÔûÌ8wîÇ}ƒEkA»…òXÖ¾1i‡¼šY½Hˆd<ºühÅêâE¥Ô‚A~½PeDðþd°óïU -*ìlð³6v9¿Ý.n”‚ìËFž/½,âЬS– ¢}ñrÖ)°fòÒ$Дøè²1üús‘0KÜ¿¨ØDÞgâQ!>½(5§N­¯ð1eÂE¤ÑkwvC݃U”ÏM-5R-*—Wˆa˜ÛZ:ƒ&>O0—¾„A±¡gJ]{ yFD|×H˜:•Ï™áPþuŸÞJ-x¶eÊZtòÓjŸ¹'÷ !p€/äK†ÓƒÞê"Ãñá~7 G„x-$¦MMP<3t¬ºb‰¥ËcÐdGoÐ#©Áp§t¹*Œ‡ˆ•]¥/(b{ûrfêch–¨§ì¿Œø(‘Uýá 'uÙ<äÙ›‘ƒfÇËQƒ^¸§s+½—»½+¹h–Ù ô›8ã* 1;úá‘ë‡o^ÁgƒˆRÎ n#*åÑ¡lK™Ký€DÕ/›Ù„7nºŽ0mPÜÈHÂá^Ò=s²¯JÚç2îÂÆã˜€_ÁDÕuKúí¼mMzùÍ*]Âo»*™éX±u=²Ì<4._K AJÂuQ=3ßÅ šÒì©ø)oƒi<ó-&“Ï©ýpXçRrŠ•³fv&–Ê4¿ ØñIb©q*ŽÑ«`èð‹¦ýaÞ¬Á>íÜêØå µÖìn–äEv1%ë^ñ¬_Œœ›½Í%ÜZ”‚l¯ÅGÅ$Z÷â°´L冩7V9è±­ß, ¨|T ‹;Š+UZG§–„3Ñ]b´‰‘•cìôe‡K>@U0í·m©²HT–Øf‚†îè@¤yWíÛê-ùX]s.]–ÄÛÒ]žx´4×›LË›ü,'Œ€LóÝ…$kN|í:Oô¾¾•+×à[X8!ñ³B Ò÷n¨Bä?¢ÏnP 2kLë!¬Ší‘p·Ï5ÖÓ “B%ìæ$ܾ¸èºŒã>˜)ðý €5YYvÓøo $ò&hÓ»Ðsúà6í%‘r=õ»p ,k7w<‹^˜ŸXvó?yÍ0~+¼`§íYÕ¦éöÇ·I â—å½/ÔÓh‹ßg߯ñF G@M¥‹^ô—jaÚ†W+vÑl¤Z “¼1w¢0rªáRûd)¾ÔÖµ{“‹ÐæyaÔ†Ð$n£î)ØÆj¡\(ªïª zß.;»ò¢¥Iô•Ô/dßz§e;Aò¦T8­yÄ&bì{âCÔ×als»’oØÎ,Ù&&аMÐpú4¥©&d,”ÌæÂÑÑï¯ |ü ôþœHm[GþÃÉLû…ïaòc3~Ͷ~Þ!~Ý <0-S¥­…(ÈNk¡à‘õi¸•×°‹ù „p‡³‚©å¨Øµ ¥wì®è(éƒt*9;û£â’H†×_|óÅ4ª2·ŸRðËy‰Kž¶”êô£CÅô{Ueù(füðô†yaÆž[™"¡y‡ÉhÁa7•ïÝÏ$U…ï±$£äºÛÒ7¸ýG*êPZ)ݹ ~s^9ÂôA÷ |×Õ!wf2Ðx °’ÍägH…#ÍK¬r]¯#ñªq‚ ÖÝï]³ÊvV_Û…}pÊb´¢~ ¦ýL!ÛT³ûüÆ£Ò]¶¼"Mõ„™I@žÞ,E£Ú1èćÃya]¥òG§®¥ w¢jz«{S‰XMµÖºÐ@<=ÇKViØ[ÖÆZ=~Ù·DôI-7Oµ¸34Äqüvn†#A°0`ykù¡4ôº¢I§-A_ˆLÁ5‡V˜/û59d»,¡ÒW½_ôYü6½‘é÷û\¨Áiÿ›#ä½vÿ7ź¹ý[¤Þq5]„¯d?if¼aô±‚ éú˜\Î$l¤Ñƒ U<)ŸmÄ5Š Þ«ëK;ßí^a•æÄ“[Ó7[G̼ûè^ãLè¾xë*s?§ƒ(QdÕ¥v‚ ¸)Ú}~O{Ö]:%¼®;%”°\:¬–µ‹Iüj4;›†¡ïò¹+Á$(j¾xœ9 Øh8Io\WìiaÓÆÝØmÒ4Âx¿ÅÁ½ßø4þ+…´%OšQtôŽq°jÉ)Œ7¶Èü›?%{¹ÒžvK?&25úÁo¯æ.Èï?ÊÝPžð¾¢²ºÈÈåRëó~•¨'T±H;!ÿ„Ÿ›§/æ6UÞ<3ØöSçá7ÞzäÈkki³¤ ߪh”#ÓýJîYÑS8ËÀÛð¸Ü!{<ªJÊ‹ÓVÒ£Aû:—åÚµvuç&æaûÐA÷oŽÛ®èúxºíl­ ¿åîŸ ÂŸ#Õ{«\ö‰y=cÅ`çîÁ‘r¬a ½—¹÷VP‹sz¼ZöšsFw’¶;&Žo¼íñòY¸ÎþH Ò§MC… [ö­ûà{¡»æ. ¢žŸxàoûæ–HÛü´3ÓÛ×OˆJ€k6™ècàiM²„C{Y€÷šªí’J³´ ©(J¢\Â6èœdÅ6½úüÝ~Ú…3äÝÿQõñ_øêÄ‚³vÍŠ¿ëÅ¥/ÝA×+<ÖkÚŠk{§aJê¢P„ñUÌÁÎF™ö/Cì–¸½agQÆðð™†>÷œþÐÂô°.I(„W‚©µ²ì N®=g5®ƒ‰~N ;eUξK IÒO“üýû¨º!Â¥?¤€©ã•ŠigNÖ\Z7ï/ÇÙ÷˜»°Jýñ´¸4_§}HÐ5óŒe¦ÃÕ²åwr0”òlH[Êâ•ÄÍ„¢c=g"øG°ãL 6/¬YÅ&¾]ÝÌX˜V‡q»¡µ­®lÀJri£3‹¸R[XICŸÙU5}9×bú&ÐÌݺž(.e¥Jü_EgÈC =Ø·AñÕî¨$´ui/mÈ“-§.3OÐyrœ£X5fÅ.•[`~j =#ÄÖˆBV>S!že7úNìÀ;¤%îBì°S`&."åЊQMŒ%¶cÇâÕ—)ó{èáõp§׬Æäÿ”[é(s»•J줠×Kþ1d(6[•J1E-õ(aQÑóÑíëU¾³.•Þh<@(îõŠÍ…›#ò”ŒoÊH”ûÓÔ£‘±hárÓà3 éœÃÝ,4ÎJÐÛÄÊÛ±¸AŠW2¿¢Z‘Dê$¼œ•Ù>V]ÝÊy‘äp1Òw+Ô-‹äÕ2xG7¢\ƒËóqt!Iã->~®¨ ’ðûn(*˜/7†ý ^µ Þ#4_¿±úZÇÏñ?„ˆŽzǽ%³išd^à gˆ±&‚^µ ^cR³æh}WÎÏZTe":t= G>}#xÝF¸7qéjÂSè*•ESºßΦ;†Þv.ÏTUhU’‰&ÚéÆÔ¡Hñ²h­ØÔVZÁ²…Ú··•# ?©ÅXv2ßÑÑ:â¶ø @·¼m£}]^. ä\Õ·È”ª…‹I;áš"•fˆUÁÅg5F±+õóÓl®¢$æí«SpÖ·ÞO2D“‡×Ó5þ1=n#ë9µMßn²¼å¡^=‰Í6vÐkIÏãQ½ey†sù±ê6*>šãÝWšÜåxÇw(h+TæÇ½x¡ÌÌ­^Ø ‹ñ ä1•ÑtãŠ%‘y©”˜µhBæIV/*ú]V.3ŽÝ–l @Q—¬¥ÆšýÁ?'W½Ô‘@ñàEÏ)rI×Z_¬fè¯ò†÷ŽP/dâÂâZZä½"wóv}Žÿ³e©Éµpéh“/,<±*£ºz§'°Ÿé+I=ýüP|Å߀Ê3³OZBÊr4Ûr‚ñF«Öm…ŽqNà÷#Z•l¹ýô£ô“i ‡W˜mÕÈCJ¦¹5+²èEÝwø‡bS*–Þ«+\rïUž)hB[âÃ×O0ßt4ßóCõs¡… Ž,@™¼Ö­{G@ÀK*£Jrí BAz =K¿ï¸R¶7ßԫµš_/ÈF&áQ3ý^ÇØFYPy:›IŠÆ!S©–›hjMh]8õñ·²Ñ5”1%c¸ŽäägÛ:]¿‹UÞÑ1—¢(êÎ[ yd3›I¯W’5À¢¬c{¿n\ð#//APÚÿ¸ ‚¹ÿÂ-ôÜD!D‰ï¼ÇZS‹‹Û”YðG 'Ísõ⾃Õþ)–öl}î¼Sš¯”[Ø/ņ(F´s.Ro~¯¶Âä\ÕxÝQ[ÓXôqÀµìK0^g1!òöTú//_&¹ÄÈHŸ 2ç÷Ó ¥|ä; ýRo4™š ;Íì1F NPEnVq„ºæ.髈¸{º5÷6nGÒî‘>gý¾• ØY°°|íÓaFÿ¥kcZæoãæç‘Žk*!ɼ¹ÕqÌüë*ÒØ–`— K¹éÑÛ´€Çú“·Ûœ9¯‚ÙG‹ ¾oÄÅýJÅ{1ÝñעР.¦—DvËÂ^ •C.¼9mþgŸGCÿ$‡Ûê]h+œ x‰HDK:’w&Áe*žc‚Ö¤œ‚5t~O'Õsî±_Ö÷kgl¹•ÛŸkGI·ßõSoø–7í#ÙÏÉg_ZÀy6t½L’j}[×ÿ0 ÇÛŠ½q‘Ï‘ÚöTst™Ìy/NGÔƒ&)$î›&lÇz~ë=¶ODðX¥"œddÄû¬5#ÜPõŒó ´¥úµÛÇÉ™¨¡ù%š@ŒÏÀÞÎWß)*IäãYzä5;‡K)WpœÙî üv2ân;lþ8,ÅÂ~±éÅç‡6±ƒ–’ö¾tq£Ýé¤è¡ÙæúFà{Íâ‹Ê±Uµ‚c~Ë4+ à›À‘¢~{Ü[JQ[âäÿ„v3~ÑV!Æ%¶Î¹~Oõ|B0 s÷¤<_ynÙû%†Ê…ày=øðà‡Ë ˜äÝj_\l å&ê66†påê+äãc‹ªâ—}¾¾†o×ÀxÄÉڦ겮õït'(PŸ£Ók*ŽŸ¢†\Q÷k/“+Ëà¾Óc!®ÝŽE¦¾Ûç‰IŒ“ ¾½ºBæ$°i5Aê”Î΋Ë{®? ¢jJˆô'uã&ƒžX ýmx|uÓèÉןú^RÁ³>ò0 ­øZ»Cý‚{ö4ç[‘ÜŒ\LØ­¦NÖÁ*I×N“íú£6ÓŽâ7¼jÜ/šC<^ø}p#ŸZDZêb¤eÒR%È3NÌX·>#Q¥P†^p'i?ò)Š 7ÅܵæØPOœyë.ˆ2ÆNTÊ|dd sLaóÆ$%í"J¾î^ªGJÔÛ&°+ñ•ô¶âCk&5·þz®þàÓ•Õ}àݯÕáâNÒì\è¹rŠ÷{ήûR,æo`ãʰXeIQ¾ŸH4=ÄÄSRÈC÷¶Ý(s¢ÁÙv\cÒ‚_¥ÿP."¢5‹°Ók½›Z`…°-’ îÀ÷NÕ£¼´£J%‘Ž÷;æ9¨Óÿüåþâìð&Üš¾¡e—eW -§îö+=zÀN%vïoÅÁ+O=]­¯è®RA¥›XÔKd¼{ï>îé?¡ dß=ÍéÍ/õÒ`”[xqLâÎÏecžUíI’ÝøèqfÅ¥½p ±Ê˜NĪXIä™[ÊŽÖeS PŒLgãâ{Äø¸#ª»w‡öÑ\‚‰ï~ f[!9Êj7Y>¬d¤dP¸‰ÕÉŠk&³wÌ%û"¦ãs6£‡ˆøWTƒïGåuêB¤wþq%­Ï™.“v¬J?i:ðÑ“ò(Ñê}v»Ã¶Ç”G4J‰a•³ssäk4Ÿ=î^èá-¹¥tY%?Ï-H`Ã) ‡Y4û~-â¸Ñ·M"QM×onxsq¤—;ct³w—7Oòñ6¦æâ±F‹Wš^Wj„þÂUšk*ªÑ|y¢åÇÕîN¢/h@þ>½/ik“&cœ]ßM:|öÇ;е<;˜×™­Ï\zÛ ‚ÒqPO!éñ½v9ñ\5ÝF}ky¼•W©ÛHë2vQ[B“hÀ¹Üœ'^—l]­ÊÏ‚'"òÔ°‚ŠÔ¦4òÈ\`‚H$ 0 ú"ij ^ß5Y »Ä?ykÁSÓ*ð7;k#Šö>F27o“D=¶[SnÔsÍœT–»z\ߎô43®W’5ÜÏΗSxþ£3–pG]Iøs{—¶õ†‚}Æôã/søµg¬íïK¨`ɨSP‘رOµ©”îúªÖ¼?³~çÁ3¤Ý|ªQ» rèy7Ýn/ýÓ¹ÙLÅÁþòÃ&ïRéÎÄc5¥( —3—åÓ:Ög¡‚¡aÝ•P˜<ôÙAr`xaG 55 f`,úˆ’Õ¤áN[/ª±dTçõbž0Eg㘬iެÁ3—DX&…€R@uQÙ½±W?«ÔÁOñ©‹„ͼ:Ž‹înÑæ5ñ<Ì%ËÉ­€I¥Ž˜ð¹KÕ´y*õDsNÁŽ×ýŸ(ÊžÉ:ùÇ„hjÍÙ¸ƒ¹×N±ë*›ó™nƒ=®Ù/úY·³()[‹îGñªÃø'Ã+_†£)5Â9b qW² š¡”a˜“[€„kO«öN´RèoQ™uÝ£Ú¥m±…|r5&o¾XRxïRΈ„´{U1›Òw!.—k VƒKêÊù:UYÿ?þ ý¿ÿW$0³š8»‚ìMœm‘þ… 2wendstream endobj 235 0 obj << /Type /Font /Subtype /Type1 /Encoding 486 0 R /FirstChar 11 /LastChar 122 /Widths 487 0 R /BaseFont /CTBMRB+CMR10 /FontDescriptor 233 0 R >> endobj 233 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /CTBMRB+CMR10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-251 -250 1009 969] /Flags 4 /CharSet (/ff/fi/fl/ffi/percent/quoteright/parenleft/parenright/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/A/B/C/D/E/F/H/I/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/bracketleft/bracketright/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 234 0 R >> endobj 487 0 obj [583 556 556 833 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 833 0 278 389 389 0 778 278 333 278 500 500 500 500 500 500 500 500 500 500 500 278 0 0 778 0 0 0 750 708 722 764 681 653 0 750 361 0 778 625 917 750 778 681 778 736 556 722 750 750 1028 750 750 0 278 0 278 0 0 0 500 556 444 556 444 306 500 556 278 0 528 278 833 556 500 556 528 392 394 389 556 528 722 528 528 444 ] endobj 486 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff/fi/fl/ffi 15/.notdef 37/percent 38/.notdef 39/quoteright/parenleft/parenright 42/.notdef 43/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 61/equal 62/.notdef 65/A/B/C/D/E/F 71/.notdef 72/H/I 74/.notdef 75/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y 90/.notdef 91/bracketleft 92/.notdef 93/bracketright 94/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 123/.notdef] >> endobj 229 0 obj << /Length1 1205 /Length2 6872 /Length3 532 /Length 7639 /Filter /FlateDecode >> stream xÚí“e\”]÷ï ©–fèPºKº»»`ˆº;¤¤¤¥¤»;”FBRºáÌ}?ÿçÖóg®yq}×þíµ~{­}ÑS«k±JXC-A²Pˆ+'§PJERŸ“ÈÉÆÁ!  §—‚,ÜÀPˆ´…HÈ)(È”YÂ_à!^!>=P êì ÛÚ¹™¤˜ÿñ%œ@0°•¨báfr‚ç°²pjA­À 7o6 „£#Pó¯®@M+æ²fpr­ÁVn@K-`ÿË“Ä äÿWØÚÝùßK ˜+Üéo›Ì@¸Ik(ÄÑh ²°«BáÕ@p/ÿ7lýgrYwGGU §¿ÒÿÝ©ÿZ·p;zÿêäìî‚U Ö ä?¥z ™“„:þW7 G°•ÄÖäøWì* öY«ƒÝ¬ì€6Ž® ¿ã ˆõZ€7îoìúªjJ*Ò/þg¦/ª[€!nÚÞÎÿ¤ýKý7sþfxw``/ ¼½œp!üù÷›É“XA­Á[ /гðÀoœx¾œ@0ÄäyÁ³³A nð-@xKü6Pà¯ÂgÎnówìoäá²;ÃGµþ²û€`ÐßA ;ú‡y9€ìnž¿×yá)Ýì` ?\ð"PwØï7<öøCÁdw…Ÿø†ûø×tþ‰ðÙ!à?ÊòÁ%’¿ îRúâ‡çWøMð5ÕHnFó7Á•Zÿü†²[ü&ø>Ëß?¶Õ?ÄÉ?µõ?4è䲃#|øì?.†þpGÎ ¼°?žÊõ„Ûí„;vÿá&=ÿÆÿ¾’’’P/_Vn¸SV.øÌà™x€‚<|þÿ›ÒÊAÜþþàá7ûßl† È 0?µ³_Q “?Q‚‚(i[ÿVµ¦ã[ëÓйDÇÂ!%–åjýÛÒt|ì-”-*Ï{2×è?QÙ£`—·©Ó[æ[é>dú§é*Þ›Î4W¡{Ïšë¦Î÷yÕ¾.¿3øØ›uÜ·—«Î$­½ö¡ÓÈ£¶3#Œ__6ÝQ'2¼š›Z'Õ¥8Š'rÉç]â“¥ñÐûHô†‹'Ðw¼Û|ôIf7V¨11®¤Q³nO±ÈÄBüWjùYy»"Ö³·ËrꊿŒ©°Wul®¾¸—•òòl¼4¦]oª¥¼]—^,%î°y;'Ú¯{3Ýö0LÌZ¹žöþÔz ½ *Àx78–^½DÏ'*MxÔT,‡YV!kôb7M¼©Õùº¾üÉ7ðÒ€õÇf¿Ø²XþÐWXŸŸc»Tt£ÁÖÿóanb”dÚCÕ9Y‰O¹Óâ—‹ªwæ­Â\n.Ó[  ]KÄɖ꘸VO`œîÞÀˆÀ–“âTs)Åý&<!ž;úõ[` µÇ¸M!›Ðѧ„ØÈåJ‘­‘µ:´gØ“n'Ôž¢vž+á+ÕàüŸB›'$­Ï°ÏzEó8cr#5ªLM}?YÉ¥6Bƒ+‰žoØ$;®Z‘ûæŸZfíxrÐÅÇ¿Fn¤QOEËÔÉP5¨`Éæ«ãÉÉëȨº8—z¥zÔo*–ʱ‡nmc°)3Œe=eBeÏÒÕ†ú)¦íó‹Ï¹Ž±ÑÅHáË&} 1P™¿Pi§"êÝ/LìÁ–þÕvõ—¸EKÏ蔑sûÊÅ›§ÜŰ[؄ϻ>lP\vkT0‡=y©ËP¥Ê=¾©1鑾µÄ°0êv}$Fi½R½Àr˜ ý!xós‚ÎHVôáä%Ã@Ñ!3Ž»GJ÷ §ôÜ®®B°}¹E±B÷'ÚÒ/ái(I§ÞQ‡€gÊÃ5Æ6¨,Uºíeqr«”¹oïžD°qô9’õê‚œÐæ…c± 8ÙkU%µÞW·ùšÞåµv…tm ÓŒí«¶ñd1^”_’ÁëÓ*ñ·«gk–ÞžöM„<”’[|¤`ç6èj¥¤ÂÇ0LܳèåGØóWéf,Õ—/%Œ¾#b[S–½µ7=¾i¡FG¥æùt‚¡K©/×1ÇŽa…7oµŠ·‚5—–@Ù;‡ ªÍÌ—V>aVk/Õ[)œ —=kb%'Øç¾~¥Ç|Òá6ub£2Xr»³Ay(UB”y‰9.¢Œq*SúK¹§Dg÷;À ’£Ÿ|{öí6ô oMûÉs-ÀöRÑ÷r4'´ææÕôüª›QÙFXhj[½Üf(Ns~¦õº±qȰçΔTv§ÑÑ ·Íõ1Ÿ†Ÿ”%ý9žéŒÏO-–ê ÇOø¿D ”ö´±dŸLG‡ò¶QèÄ{ÞòG<¼â6å&ãËC¹Âe¸ Bó)߯ÀöCñcÕ9 ƒ‰ê U„î¬ÖdÙk2ØŽqé-Ü–‘‹¤’½#L TÙŸJ,`åm}ŒÝx"PS£ã‘ûb½¼©Ja*™+çmòL? ¶ÝÁãÔ{_WµqKxsÔÃÿÉÚ‰ ö~™ÂXÕOåí—C‡}ë]ëny7­%&5cüúf!oAyä>jºÝ #( ˜oÏ.‚O ")ív½År\mφ3ßöô‡.¥òzçÊ»GûÖ1·–_LˆOödI1ìf¥GC˜©—ZRèýFóBmðÅ‘EÞm7r¶#Ås”¨7/nˆ…_MÒŠ:E11²dÊH¾;k¥5›¼0§øÌ¥AQB”(Žvå¢p÷²íHÙŽ0e>UØ‘ T }ª`©”ÒÎßä¾E˜#Aϰ-.¾µäY´ülÚñ˜]ûyy/·Ã˜°Ç™œžpp»‘ B÷aʯ™òy™ƒÓ‚ù‹@Þ º uyfÕžã2?¿;»Ä“°Ôc5ÚûKåeR²9Ä£Rõ.»ääW "ÓëY$ë(,Végå.îo¡c…ѦQ—ëS•&!ODo9ìø°HÏ"™Ë‹ðŽ©Qoÿ…‘9ÿ…ƒ7zWÊ-¿(Ò¹¬iFÃ,’MP,4°,¯ƒ+½sLÞÈÍÖyP³Ðªå‡Çu÷N‡Ú+ßË;¤w8Õ—|R»a—t­ŠØ§ð¥RÈØv<ø*†^|öÓBáü‡~0ér›´¦úóЦY­¬å/Ñ$6å•fî ò•ÂæÒ Œ4_ÝG_ˆ¿Z*TÖ.M£ùP–¤$o7Ãý„ú±r©ìn*"ÙÜ»T/&Ê¢ì‚êÇ%Û+=­” !ù8¾öÂG]Ÿ^zZ–é°0F«Ê“x˜‡8n߸"î@= oúø¬^`]¨²Ì¯Õö›ÖM~#Uß*«pa헼ЎR_ýCNŠ÷¦$G²“#€l/Ì\&’4uìI‘GG^õÍ©GÐ`Å¡Fm{€Æí8;¢N"EIú€a‘-Ê8²S…\ÕRKη¹éÔOO|êë71¢,@–°E§d\éžÏ óÊÂEQ2wyÚÒ!eņ:¾)Í«ãUk¯T®×)J%s\«fZвϋ&y . V¶•9t¹ƒÚPo;_ÕhY*y‘½z8,q¸ª£h,Åi¾F®å+.+Š4µVš+™œŽÞtj@:I_¤S¥¨]Çùkš “vƒÈ0eIð#+W>—ÂFÂÑpŠºª(„¤Œ´,š¢Z(Þ {2*šå›Ù=\0P îð4ªC}óI?ãñ%cEYÒ'c⪞*Öh®g›©·Ë¿È,1b²E5ÔçmTÞr©š#åÈö»@øÐ/wÏÆš?¤Õô¹ ®(ÇÉÝ ¡ÈÂxX\È8ùÝ;/œu!#ç¤Åe8MRHkB~àyR0n†wêIÁ`gzú׊ÌcëÆX°ïãQÕ†™Ë “7$Ê$¶QüwX1(3©¨Ä¼É0ýtŽ©O¾‰:ïpQìôd—ô pþÁ•š·žÛ£ðþW­B¢bä]lí!)ª…½ƒ^YœºG‰Á„µŠj"WƒQÎXþ2³‰}¦~±í_9ï‡b¹Ò^H*~|ê$ñ5ÅXXX³:ë³êåëç½Éxªö  ÷ÏÑ»š”P«êÞ3Yà·ÚqYö-®‘í â¸×Ÿ˜HÖhJ~–Xà:÷m’Úïôå¯W(~G¾ó…Îä÷+« ÜVùÜa=+.a†ó/Y ·ë~Çöµ—TJÛW¶äÞà”ù¨ïóvüÏ9XIÎ'c( à‰JŒó–ì+A_÷—3 Éu-ªœiÏ¡ 5L#Ú#¤Jzò(£8ÁÙNô°”¥êÕP¿6‰²yÛÂNqÇ·"u¯y'9bqƒc…´ã¼ž4&p‘Øøj!hÏURl>GŽjOrá’JËk|ÎÒ—óÚÖ(œqÉÈÔ8˜ÇôÍg”ÎK=w£Èí(ÏžØ\»œðq‚?Òav8Ó·¢m³?úJèÝSd@Ë FÂûB”×-ǵ\Á_ÊÀi'ŽÄ†Í<¥š¬S}ìD^#>M1ä+è2m÷E2wü÷æÓeÍßs’ÆÙ®”Ç‘¤84giswG~S¿ÈÚîti™¶ù\jͧSæm¤¸ÅŽ_7ÃÈñLŸ®Ë+AªBg9?ò’žþ r˜säÕ˜û¯-Šð"çKivÛõ7_­äÌ8gïã g7°»Õ±ÄÅyD#Î\ ÇÌ%æªIÍ5¶}vqõq‘¶Xi$ÔUÕ+ôGÚ(õeÔr'ŒÓ¤jBÉËŸ(¿PͲ†>I̾\,ï§ëÆM¼¬¹˜lmŒk<42\|Ào#Ø}î˜Ñiß=§ÄnÌÒVâh˜<5 jÖ+L$ðÅÙ8ÍEòf3[yÏge[f×€o8,È#ÏÌü1Š­p[ÞŒ)9H8NoZl&¶PA0Íš X&*Ó3SÍîÛBlªXŠ­ú†¦‰-,µ÷T0,9_¥ÆNJg²Àýb¿ò¼ÚS=åÃ` füÅ ¡qK/; /ø#dºùv)|§¡ ?†î­jË”•Š&~Û„Ö½|V`£ä@Š´4 ‰vc?u†'±ÀãÊå®4¥¥Ù ‘¯_•¢.§ÜùØéèѽu¹/ô 6/{‡ÎBºx7(ëÄ|J«> ¸+Ê8ˆ#[£òLÓîÞŽ~JD÷ÚÌÃ.„wE®*¯ŠõÊ^3=>Ô%a9æzÿ4Ä>!+ˆ2DzDÂp~{ã~¬mqÂY€,™%§•O˽ù¶FšJîÐ%õ¹¶Ž~˜caª'NÜxÞÿdBX—\fÆå~ò7SÕ¼n©Ë’(ƒhñ~|Óâ ,ÈMVTñ«v‹ ó X³\þ•¬õ ø µJ+]T´ãêûBí¹? #=Ý@áR%tã“É„;Yq ]­U¦S‘_‹ûÆð7 GÖ³‰ô(.FqÆm6˜Ao§ÃëÄïz Z“Î~¬ì¥Ân>©øãßðn÷]·ñ7(KÖ&âŇï$ ©3ÌXÔm›&>ëÆã kHÕ©•~¦ì`{•€[®¸ê±A‚”ý½­ÛkG[ˆóCB†gžATkQÌc¨â6Þt0ƒb†Xô'Å’¡/ŠÕÑúrTKª•ÈòO•¢¬×íDî®™¶ˆ×Ïõí ¨ÍB¾ì§psHM2Ü‘æFðßè“-{ U¤œu¶æ>õÕeÜ*½ 2Häü.-„HyÐäóÖ iò ©'©K éu2êSIaÉÆWriÜtÇÇ<eß=¯W+1“Â9Ã\½ŒÌÕÃ@¡Õ’6Ù«ót¹nuéÜø`}q‹ ™(ÏCC­§œý#)9ûöÕ*M6û@2Oýî¤tòWª–¾W ùñÕ‡&©ïˆr4„çk¯äЛ%¿¾ÓX«ùök5~F†è"©ù3›y¹Ý\cê'’îsÇ€¥‘}L_®‹Æüqkõët¢m%‘“Ôªa£5ã’ô5J}9ì%yìô²vã÷£VWU^6Ùlžáp,‘æ y ¿UÓÁ;$ÅÁý•ÞÖC¯ˆ§†ž+ÙΘ6¨[E þ•Ž‚º³líN¯§xµîB­E‹äßhÜ©œÙFÑ¿̈ÛßC÷f›P¼õï²Pðº¥VŸ’pµÃÐÓ0+õ7b¿öië¤ýHY)SG»|®¡‚éªþ¹}Á¥ÛDüÐ,9kc%gd²#Rç’UáM(¾’ºK¼Öà‘÷ ¾Ûæ[¬DMÎ?=#þ…lÖµÊËÖøÅúD'á¼O¤¤-V±#(~¬©=[XG.šk¸G8dÏs?ñô‘Û›Ö6VXìàòƒ°Ë‡Ò[Q5Xö”ãDe¼«eng\÷|…VZÖ¾E-!H–±”Ü´ÊcC˜þŠKKâgGú£Ó ¥l_òkœ¨_ºL4 y)a…aDMV~n‰44Dÿb½‰Ë«î9ÿåö~ó`ŒçKÇœ½#oÍåá)xÂÑ£çæ/?.ÜæÁéè¿5«îÔ­޻Πq˜iâ*')Kïà°|B˜ûTlcì°@/…ô¢;KÞ/e q€ÒC›×¸[7Z½]ªº}6Žunf蓟’¶wþÅ^¯;金ÿŽÝ¼ýͶz¿f€ƒì6Ñ9j·§]wã±sl‘D†rakø:ñ8‰ÞÈR™z¦œ–“‰G½s7}töjùç”9 $‡Z´kìDôöÅbš€©¤¤•nwîaÉ {ÌÌÖM…QbçµÑÚ`¶wíßUrßdß?‰Ž…z‡×öaøÜì¢ÿTBÛòxéu‰nˆàp°kxœiN€â^f[ÀoÙ¹ÏI{ãâ>ëá'”lá77eñéWµýÇ›tç˜O›&Û‡óYøDŸØrb®EùtÞ/yõôôsy{`úM͆q FëløÄ”,g§•©[UËÕ›3öiÇMls …/å:gè"l´On‡*sئÊ}£ûoŸKÎÏd,}–ãD^Ê/rí£®Àœ®(‘D¾›qïMY¬¨ në“ðZ;Ü^WyÒ‘©G¥ÍbÖ;‹=å[Ì?ȹ†“ÝôPÚÒß$§CŒ¡*µØbV}éÉ`)B>Ê|d«›l ¥”:ˆùe0µh{Œ}ŸÑC Íœ È÷ðËoWÖs^¸ŒWÿ;E%ðJ®œÖ”¿";øþ¥ÈÐ÷Ç‹þqB*j̨W^¨LFãAË®¹LÁ;MdÂµÆØßåæŸ6 düòh·ý¸);øþ®Ín@[¶æ)¾þ-¡éŠ^ÀqM׈Èy@Õ§Á§xcJÕ¢&æ’lcÜW9hÉ»š,¼ÉYpBßîÚª1»ÿºôÌ15r,}Ķ~§LFºOùBag[áÐrPr‰Þ~r=#_D…‰W½ g®Ý် 麅Ö™})-øKmTïÇ]ö5L*2‘ oŽÕ¶ ™]ž×6Î3ÊØJ0™×_”>¿3 V E%ŠæÆïtFG1µ—m‰pü¥l+K]ã?ØG ÅÛÃeù•4òEGi¬“4³åÝÐH蛋sêQ±'ÙúËÖtXý ½º3!°%ÃÏw®¶jë§u‹xDõHïøHR>’¶›>ÿ+D—Ñ»jËÇZø´;êÄóœõ¡á¹Iúãf•˜Ñ–_èm‚´ŠU6“,X–KÑ…y 2;óEFJbë'¡2%+§x\AÓ„ìuM‰Å~û’kƒÑÓžäR÷¦à_K¸Û&×(Ü,áÿ2³ž¨I‹ê(¦¯aO‹X‡gGæƒk´Ù$½©8^ÅÎ6 oq5³"U‰±ˆ˜îÞÈ–u ÞqoîˆlYá3‰êÑ£~ËÐ/›?£Ç-8_*¼™ÕsÑŸ¹9xúóg¹ŒŽß9‹ÆV\<ŒtgL‡¦šàÙ.4K>BÚKiHO"™"ÝUø^»;:Ö75—P]Ð,¾YH•\ù5¬âW„ÓhkÎ0j€JŒO Æ­W÷ý1ŽÇ–´ƒä4•ùD“÷ÎjûI™¯™¡&]Ì…`Æsú¢yO^¦ÇM©V.ãÛ™ÐzJäc¨Y,g# ¦JúÁ¬ê}G7)²ÕKŒWƒ\%”MìáNZhFCóˆñ¸öð+Ûœ«þG“‚ŠV.¶½ù±£'Ù|¥$MÏüãè˜62Ç}œ¤ÅW¸¡™0QýGçæÓO–èÛ¾ºà!ƒ'y<ãÎvåÑ®ØÁ[õψ?á ‚ß îbö–Yjz¸FeÓœÏ÷QEQ+ÕxÜLùü¿—O3<“ñ–‹Ÿ<¸=ˆÕG·pVFšÁ0)¯ _iûñü@œ~¹†5É=kWFÎLO¼ÙêÖÌÏc¼Ä'ê={©÷‘ãÿðøÿ þŸH`å²€¹A,`€ÿ±dúendstream endobj 230 0 obj << /Type /Font /Subtype /Type1 /Encoding 488 0 R /FirstChar 11 /LastChar 119 /Widths 489 0 R /BaseFont /XNOKMD+CMBX10 /FontDescriptor 228 0 R >> endobj 228 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /XNOKMD+CMBX10 /ItalicAngle 0 /StemV 114 /XHeight 444 /FontBBox [-301 -250 1164 946] /Flags 4 /CharSet (/ff/period/zero/one/two/three/four/five/six/eight/nine/B/D/I/N/R/S/a/b/c/d/e/i/n/o/p/r/s/t/u/w) /FontFile 229 0 R >> endobj 489 0 obj [671 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 319 0 575 575 575 575 575 575 575 0 575 575 0 0 0 0 0 0 0 0 818 0 882 0 0 0 0 436 0 0 0 0 900 0 0 0 862 639 0 0 0 0 0 0 0 0 0 0 0 0 0 559 639 511 639 527 0 0 0 319 0 0 0 0 639 575 639 0 474 454 447 639 0 831 ] endobj 488 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 46/period 47/.notdef 48/zero/one/two/three/four/five/six 55/.notdef 56/eight/nine 58/.notdef 66/B 67/.notdef 68/D 69/.notdef 73/I 74/.notdef 78/N 79/.notdef 82/R/S 84/.notdef 97/a/b/c/d/e 102/.notdef 105/i 106/.notdef 110/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 119/w 120/.notdef] >> endobj 213 0 obj << /Length1 1167 /Length2 5165 /Length3 532 /Length 5923 /Filter /FlateDecode >> stream xÚísg<œí·µè5"z%JÔщ½Eï¢d˜‘ÁÆè=z'ˆ.D Ñ#z” %¢Ka-ê™'Ïû’÷9ß÷Óùûþr¯µ×µ÷Ú{_÷-C!e0Ò¢D …€Â@9€ªž±(,Jzë–* B;#j 4D”•”=ÄD@)9qY9Q1Ò[U¤›/Êù! àSåÿK$ P†CPÎŽ @„†BàØŽ Àéè Aû ”a0€ñ_'<ÆÊ &`gG4ÀòÐA*ò—m„ ý7 ötûOÈ ‚òÀšðaMò°ÁH̆8‘Šè#±µ X'ÿ?Lý;¹†' ¦‚ÿ•;£ÿÁa¾ÿ'Ž„»y¢!(€ A!þ-µ€ümMvö„ÿ;ªÁœ•a€èß”³‡†³lèŒv„œ@0È/‚ÿÛvl¿,ˆ¨š˜[ªX üÚæ¯!È6õuû'é_Ú_øcgƒröÜb…Ø÷?_¶ÿ*¥ŽpD‚Øë )¡P _Rì½À"I€?àŒC|¬_a=ÀŽ$à„D‘þµLì¾Eœ~q¿ „$@êë… ~SR7ìÎàß” @Ä‚Bþ&d"Hä,) A{ÿŽKb« ¡(È 1l]¤'ê7!Ž%œ½þPHD<°Cøc­y@¼þp†mXäïþÃHDÎÁ:uD¿Icëhÿƒd±F­#lŽÿ  (6þb›€ü±~œC VŒøbÅÈ? ¶Ôð¯^þ€ØFÐ@lž@¬+ïßûÛ‹ü=•ÿ~çTT>þBX…vØ“âiIÑÀÿKèè‰BAè_¿3öæþ;9cï9âq$™B:Þ wÉhŒ,R/­ ¸}MåaS²þË®‰×daŸR®ÁJßéºß^¨·<}‘M}ý+ÁWvïsfØö£ L¨{ræäåW¯_³ýZ˜-÷³õ|¿¸q‡mQ¶5~<ø.yÍ`|a¨<ͪ¸/o÷íV¡!Ÿšé:Ñgœîû^ Ý9áRÒ–Ù0³¨ˆzqã™îåÑQóÞ7ÒãÏ r‰"n˜ÛC¶{Þ<-".H½´9Ø¿{Ÿ.wRÊñ~r:‡AAqñZìñE‰9-­ç§U¹"J£â<É™ˆ ¹© )õf®Ç“ï–™ò‚„}þ1TÈtõÓ^…ûCÐû5›Î¦þÎ CŸñÅ¡ü‘7—†·N)†û0]½'ACÛÔó‹Ikøîoç…UÅY=¾å´»¯wF?uHõUÂXÎK?Þ[õ“ºç–¢¥z\T£å¬“ñ S! Ê#?]10¤1ú9ò}™ôxÙ`ÏÆàæóâÀ™y¿ÍZ£k\Ô,$Û7îLq¡Å§òŽ2­°½{ «­û›’üˆÕOSÚÞˬW¼.ÁÏ{”Ÿ–¡59•N•‡ªä*d¸¦.6eÐßõÀû)C<_~dtÄ<|œnF­6T^FÏ$–ÇXrQ˜ViÁнÏ,ÎÝä>¤æørùçš ÛE7nÄÕ"*=m]Š¿FcV *ê‚—8#dW̹¯ Nåø‹¨<¢¡N…†ïÁ¶*”Á¯jg [§d"r÷¬*=naè[Žõ‰0žË¤Àþk,”§YMïMslÔ¹FOç]³ÆÅ+ù„vgØžÍÆ/Ëâ—Î@'«ïŒY2/ÑQ1w•пuUÍ„ÌÌÜÉ^?£ª•|ïns“¡~Ú׋5!(okÅÛ„y2 ¨øšwõ&¯Ï°ÿS\û§‹1yAdiÚw2j6ûð¶ì¦Ë^8 „pà>wv…4“ÁG` Å>¸‰B‹ä;Mw~²á÷}ƒÈP ±Ô žàgûÓƒµ2oE\|goóõýˆ‡Û3õÄE‘ûqÁ”Þ+êJÈ<ªõ™Cz:4’ܬ¤ïSAutsä M’í„ËÑ/ãŸQ©Ç0îv\„*­8]U‘·w#ˆ\dcÖCEãøK?Q¹úÈÓ,Âø¿¼,KžÔ¼r®˜ÚàÊUéF\šu|ëØN%R{ZkC€¨&µ#A Aƒ¹§ éÚ ƒ'ÍÆƒâæÌv"rx.ЛäÎAï¨uXŸ¥úÞ,lRq&ø4Pº|‰‹Œï 䥚ž=Â;ƒŽkÇ9ÝnÖ†¾8Þæ Nxj©Ùõé®öãQä ä¡ãcY|'“®ËÎÚ—U{Ö².Of9'˜©Žpôì8ˆ…òH™‡dGItAÊ5Ήm_…~Êçzm-•ð黹!’ωÿ|‹÷ËAÇ ÛËîùN E­’ŠNW ŸùS6bsãÑ·!VÓŽ¢ç/jcó?ïE7Ëcš\Ž%[\kuV¶™*bÓiÍü<¬ŸÇeé÷6ªT°7͇(-³+;<ô×…ûáí¢¨C__“gÔäBéÑ|I jJ[{Û¸‡ZCbÏ:v¾ÒYŒ ‘1Z-é¿×ûƒ¡}š‰ƒç~õ1FP3aî ¶1.ÙïdíÝßNUöUô§boÀq¢ì]ùÛ#öM ©wz‡á<Ü„áÕL¸„®7JêËYQ0™ûâ˜?áH4 ¾X ã- ¥bƒ”»&Þu—ë;ðÉ”þFþš°2u¿i'ËÎ%VF¢ßßf…³UåPÚÏÚ¿¹¤Ê-õYz>Ê•Ò9I,Ëœâý|vJ”¬Îð3yS›¨S^º†,¶…>’…¶§î”Šé7ÎHti£Ø\áoÉNÝÔ`I„äí’^𝤴Ðú¶Õæ8? }[aòÓ `|É™TpÏø Q¤ö-O;Ì@N¥b†¨<ÅÑq îuO¾êˆºÚ¦¦WúGÆ/à™”kœs׈"ß,òZuÚPIž)v‘u9 ¸ ìÔ_Ïd±¢šxå‡×É"nWpÕ¢­Y‘ öÏÜÕ92À»zú°=§ÅÆw©˜ù®»˜jÙšù‰ìáwKËMùà¼V ·z [IÁö¨y£ôʼnkÕÆz?Y©äÕ¿µ<òí¢…OŠœ4™’•>Ù0 ªU‡›8¨Â¡lS÷Ç«Ø($ƒáÊàmh'LàñAç©û ®4ÈˈôºøOùl[WoC7­¥ÊÆTZ 9­siš}^tŸ-Å“ìH¿ÀÑ|eW‘»Š¾hä­¸¾&în9 X›Âð§ ”o¹žò…<Þ÷£úÙ¤‰Êñr¶G–Ô«9/Î'¼@ ñ¥—'ªÓ8ˆ1ôÁuô› ¤ËÙXq¦óUlõ¾¾™\kü-2JMÑÇÉ$Dx?ø¹fÍšŽkËHÅþc­P#ùÐS÷°~+‹ãŒÂ¢ì#÷½÷iàÕÃ/dWö˜×ûÓ:1—„Œ£¥f¾÷"uéÇËâ,Ý«bØ~<‹&3èÃå3 0`i’{ìÍ%G¨]jySp3k…ï>ùúaÇ}äÙM¨9cC1­‹x;¡OC_ާMÛî´NÕ-iÃUêÊ[1¤K?¼B×›!» ]À©9æWﮩ¡2ÊLtâóçiùK5 qng-Š•2}¦ÄœÑÞË«{½ùÛ2!9êŠE—äÏßkùà®mGD‡lG`ò5NÛù›d:p3•ãp@´Õu®YfJôEy|iËûÃŒOšŸ©|BI[7‡Ÿ“ˤì$Î=©ëZ=×/üB˜b|¨×yÓΛ÷¶mxùìZÔJ!I}¢”B¦mƒjžÈïÃÌj‹Èõ…=oïýž˜;6[Ï ÷xD;î"9È BDhýë5rx9¬;T´|@æ™y úƒ&†o_” ÏœäË…'…(´¿‘WueÁY«Kö¨îö=I.t×»&´ÑB½G†Ö>Á}þYãC“•ó4 '³&›’Ž‹žåµ/Œ’ü2À@¶}›D˜à{’ë³[±‹bUDô*8?Ûwî‹É½Îi“–ã»7†+ü£å5Ù^fú¤z®DM(õ°çaðò®«(ͳè• \)þžMñwº‚ªÐʺ¬9¤8a©Ö$Rm|U¼B²Ü¬L3BÑ8È>í Äç˜GÀ›úóì[v“ôÄeòfïö8{“í£?˜íÝ¢µ§Ì]Jã¦ÍõQ3ÇcŒ·2izÍs9˜(-§í<¼ ä~ô ½h ÏÏÜlîˈKL|±S&GáÂýòŽÁ̰×üÎG¢à¨ÜNÒúÞÕ´/Å“×oì-X­¾/]„i‘!“:bL½Âm÷­WÞÞBü›z—â'ž¶YeƒŸöwoêp{i(ß‚6é-¨‘2…ØU°Îà2³[¦Ÿ|rI«< ³,0Ä—u2wE™ê Œy1[q3˜€ìõµJ"‘QwD„'¦¬M®W,&ûòaÎcl›_â„nçCŽ6)™rß±nß#V½p4e{™—\/‹ÈvQÑâð®'çÐZ¯'x—2íø±»â>±KQ¸•ŸXK£z¯§C7ûŠwçÌ=‡ý,¬Ú>ó‘¢”ÖÇ‰Åøç§‰Ñ ÝQ®ðA÷àÐ ´œÓo[º‹î+±0>1ñ}~QCN#…–!r˪Ä'*TåŒ1/cÐ+(~˜šýŠÓ¦ŽÃñ鉄§°)3¾ÚöžÝ2¡}4íÖÛ˜¹ÚE‰ÙCf—9Þ,ºÖÀg¡2)A±¥õŽŽ?┣-Hì²nBkx/\;dÛ7ÓºoÎØ*7ìYÜÉdН)[♺h-úBTÄ‹!IÀI L¢XÕÄœ°³ôUÝ('Údž²X.YZ{C«Ëtêþ(y™xôöàêqæX w8Îð~ÍãKd nŒr·!׬kJ}ï…3ŒUêjPˆ[‘¸ ô ïm°æÖC‹g„«ÌÖ?ú¤_`ªŽ3äñx\e퉗úö‚H æ_z¾Œ­-VdUüÁÃZ¿Ô<~—ýNÝÎ.ž¤²B(‹“öy²‹’B,-4X{ÞP/üú`ãØgZ»ïà¨@ïÔÉdVŽv¸ß°!Ë%‡¨]ÈfrMÈF©yNÐúÌY´p]½FOŸ§í7zúÎÀÔ›!êqýøšK¯x0G äN1 QLäýÖ'íeošbZs^:¤Dùñ*ÕH ’ZHÝ \çð´Ø&õnžÉ Ù!}󙽿"`«PÁÀðdÒ¼š nfîíÝREKÂem<ö¾K–GütSOú¾ôqO}Àë[¯"mÃã—{¤mPÔDRRR‚qH¦dW²f› ¯<žÞ,ÄÉ>M2.é¶´Ý&ìz¹ZÑQg°ëŠ—›v}³ N“1ŠzãFáϸQ•2j_üC:)×ÚͧYé|“ì½ÒýpoØÃºª*&ê&|'áÌ…åq9µªØkRåq°ZWkîæEª¦½FjÒsßVYŒÈ8Q÷˜”Loß»xIÇ?ÔØ†ÓXp–d¯eæ Af÷"«¥Q+‘-±…m+$&M»Qû Ó*;îZ5«Rý‹2N—îÛ8D÷CÀ¤x’K¶ê@ñÏ>ˆÏVPËÔÚÜç»Ï“»º,¾Ô¼ŠÝ7sš¢ãò- „ÍÛÔ”ä²rÃöýÍvhÃæ2¹êÎ/¢¹^OêÖ(¾s+Œ±V\˜TÖŽcò¿æe¶˜õ<‰$`é”âç¢MV›ˆO“ ´gZ¡_e|=ºôØ/?` K9áû”˜¡©×¾hbÚ@3T"Äåî†ÃD>]%ÿmе•$ Äc—²î3–TMî`õ›„viWøö-±‚¼Á«~Å[Ús•©“×W;!çžH~›ËM3*LUÊsq´†Û®k…ÿ™±J+ ÈVbÙvvønÇ­Ÿ ÏBN6T:Þ¾³\`DÃZIfzl4¢“Â-]ÞɈpˆÝá¤éí>æ× ¢Pp×£¹ÊHu`¦Ê Ý[åF4øÛÍ>Ã0”+{‚ô¢Ž”5˜e<é ]Q\_ÓXg):®Ä#¥&ìZT¯K Kèôp¶‡˜¿3^{djV$Ú?@ëÈËßêëU›^såT¬·DKÿÍÃË´[¯°‡ó¾Í"&‚wœ£¯i¹Ñ«XY [$J÷-ŽõØxp?f±eýœq÷Cî`T4¬ì¶þBmø´¹[Þ Šþž§¼‰)ây’º«FKz×g÷-æ_ô1¯ñÚÜ^‡Â[XÚ DÜ•ñ5×x›øZ®µ@Üôè}À'—¾ûUƒ©G_’s‰WhH4¥eá‹ÐÍB5÷¤åÁd/¸é¸°r%|½4E·à¢'’»»p«`‘˜‡ŸÎ.ùýufª¸7òú_ŸÛ®³•^£7ÛQGw|CmVß÷IȈao™¡0[¥q¦H!~“òJÝd:òiÃM×Ó '¿W¥2\Žé{îûr‰]ÁîYv||gÁ馟b4vÙÃfFß1c²«Ë¥Áa§o¨Ÿ˜c.8xÆ'žÔéõ4VÕO©¨ã†GƹU»€º¾áR2¶±Žw·yT ŒØ7 :÷ñ-åþ8Wó8ŒMÒºÞª$I=ImÔ¨3j[›[!$’ØÜq!ž³Ö,ó\¼Qn«¦ÜH"‚«Ò‡u0wŸÜ°éSÕJl°›;Ÿ·÷ÑàŸ{× ×è„•ãé â«li°tó]ètßÒ‚õ:%qV|þà'ØÜÞŠ’A=® Òbé_׺M2¼¾K€G­IÅãô²àJŽªMiÒ ³mwåë*]L¾%ÉO?±k±ó ¾vüþ àH»oBÔ›ßÒ#¦ÏOг]³æ\@JN¿‰ÒÉHH¾gÉbKãâSîÉ/GÞå{øsê¸d­ENaž0иëÈ  Z î1—Šø¡ ·—Õp­½ïq¤ŸúƊ•s-0Û]ž×/¤Z³†ÉG‚ß’f:V¨wç×Ó¨Þ?¬½ÎÊ8lO«r&ÔpyÊá½øÁ"­R³+Û<Î¬ÇØä²°iv÷ÙäÛñœç»ø­,.Öf–%R\Pº¦'õf>Ž·9dç VGÆô)f"m¹ Ý·%ˆX¯I«ö€'ø'â4øæíφA•"¥©¸» Õj#,/Ksj+l×à·’¥æo¹°|)!sEv¸ ³Ø±xì(»£$õ®øæŒØ—”bçÄ +ï-'b0ç.¡P+µé ¦ÅÓBü†ÙǛÖ2øM^4¸êtÕ$õO|öÅ{Þøªo;V'}Ò¿Õ¥DU‚×êá"N¿Â—'AâHAfPÞi¬Ñ–#¼)‚¼ùqÎV{ˆg~??—9„îv¤zƒ®, ˨¿h°¯Œf{è^ .‘§³Þ‚¯õ’aQ»7ÛÚÇI%¼+­Ø|àœ!ƒvÏä×ÓK2¥‰]®=ÑÿLJôüHàƒ€Ph$„r%ý/AsÏendstream endobj 214 0 obj << /Type /Font /Subtype /Type1 /Encoding 490 0 R /FirstChar 11 /LastChar 120 /Widths 491 0 R /BaseFont /CSVXBY+CMR6 /FontDescriptor 212 0 R >> endobj 212 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /CSVXBY+CMR6 /ItalicAngle 0 /StemV 83 /XHeight 431 /FontBBox [-20 -250 1193 750] /Flags 4 /CharSet (/ff/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/I/Z/c/d/e/i/n/o/r/s/t/u/w/x) /FontFile 213 0 R >> endobj 491 0 obj [736 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 417 352 0 611 611 611 611 611 611 611 611 611 611 352 0 0 0 0 0 0 0 0 0 0 0 0 0 0 443 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 741 0 0 0 0 0 0 0 0 546 676 546 0 0 0 352 0 0 0 0 676 611 0 0 481 488 481 676 0 870 644 ] endobj 490 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 45/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 73/I 74/.notdef 90/Z 91/.notdef 99/c/d/e 102/.notdef 105/i 106/.notdef 110/n/o 112/.notdef 114/r/s/t/u 118/.notdef 119/w/x 121/.notdef] >> endobj 210 0 obj << /Length1 903 /Length2 2050 /Length3 532 /Length 2668 /Filter /FlateDecode >> stream xÚí’y<”ûÇ¥©‘%»òDöeflcIŒ­ÐØ’%T™g˜1f˜ëàˆÄ)-#J–œcOD–$DŠ(*k"E]¤²o¹C÷œãvþ¼÷¯ûºÏóÏóþ~¿¿Ï÷ó|¿?¹}vGÕ0xª'dA¥0ÔPê(}À{ô¨.€RGÂääLiÈ R)f ÒPzz(àh Z_SK¥“L©~!4¢—7P4UZ/B_ˆFÄ 2¼!_¶$G©8"ÄQ0d2à°~‚8@tˆáÕa(€'â€'äE¤Àë†,)*€þÆøý‘ „ht¶)@‘mR `[ÄS)ä`*»Ävòß0õ³¸E™lú®Ë¯éoiЗHùWÕ×/€Ñ,Ñ(?—:C?¼a!<1À÷ç¬%$qŠ?BDº1ÂÛ8o€’éÐF¢à6ÁžÛ†Äq'çcv*?ö¹‘³‰†cˆßŸªëÅŒú‹ÙÓ¡ƒ7¤:‰b²ß?¾<~êeNÁQñD ûBhë †ÀØ7ƒMÚ)x(€‚Ù†ê*ƒ}`Ï$ Pi°õujë•ÌÞ$;¼A#„ÅŸÄÞü“PlhjÂ&ÔÄMÈÖ&oB=áû¢Ø}(›­LÝ„Z‚¶ ucÿ>ij0SMGPÓÐfÿ:RG@ë Âÿ­@£AÆÆ-fïë&ÙÛ… `ë}MÅœ!±*ÎæE˜g?ÏçQæ4ñºwѦìaWíŽèž$NòoO­ý•K]– R…øFyF¥ƒV$éçî‡Ù?³˜:í1åÕ÷ÑÀS£©¡U’.ßR±!üdæ£ÇwÕT¼œ™Ðæ´ílÍ»ìz«éÆ—æñL;E3DZmû8êÝïÖ§ÑA»X¤’ÅÆ”ÊkîsàOñϋӊ}Ä9™ûMGt)–·R¥ÿ+õ~€àR6oÆ¥ïî3Ÿ:ÝD-£/y2.PXáa}FÎ~ûâ"^Ɇèh¾ t†ˆ$é`Ëêëýñ VEzÍ©ò‡…–BNÄ^y,QÍÕ[YIt¸+äÌ)Þ¡ê rĸ˜Æ1įËpÞSùþ_±5[ÁÓ §Tô£Vs¶°Å¾[–O1åo…– l5o{DÂ-|°N.ß¶kº‡—³ŠïJö~`h´¢C0<°%Ù®ƒ.7h“¡· qHbHЊW“f´yB½Üê¤šj É㳃 ÕÇOv»®*¦¥ú<¹ÆïáFžÖ¯%Ý=± ¶JP9ÕlB?g`«¥Ìsª&Œ·Èd1P[:Gæ8Ÿ¯Óãå!RäõGÞËê[lsÈž­Ìº–½¶î>?¿0Ó¼•íÔù£…©Ur-“Ãq,[îåŒGÜd‰¯¦kgšÂh Ž µ1‡šÇ‘±²ò>”÷á¸åxúžœó V£õÜ¡W{#¿X}5•åõžìXrY™ ?mßã°j¸ãKýîV\:U*ã#E-.µgN%ÈìÔé`¢Žô |6v›¤b®"÷u ü$“æîOÁÚaá•”í©Þv>-žÉZüÑg3øtQóúÈóèØ öæ«ÆèÊ…‰C7ô—&xü—tïÄj¸ê\Û[‹TºÅ‚Ð3•¸¾Ë+¹Kˆ»»¿F %n&˜{傲†wÐYb¸–ã2Üuñ£¬BƒÔ²NîCúifyµÝáù Üø¦KÝÿ4—ÊØØõ.¡3¬gE¹ü®õïî|1ÙÛö;iÊâÐPž€ÙaèhlJ¢,P ¥ô;Eü/KýVy3“ç–T|øR—Ó¼5É)W/þ†IÄûú5®a=ÑüJ©¾ËŒsœq³-‘û^J‘ ÞDó4DŒKOô^¨EqLH&ÛÛiœìˆ\}w.ý êü4dtÖ.'&ŠPב%¨ÏêJ›i«Ö±\.åi0æÐàS~y+kô}Ùó᜻û ‹‘w~°Ïö5(4ÖH1•lÆ"m¬‚¼o‹òF;%¦éŽ øûYýCIîÅဒ¹à¤GgN•‹âzNçÎ h•ZGSYÕo»^C?ª„©~€Í{|¤tZHõÙ¿»Œñ ®ô¿Ii7úþÕ^&Ì~B4÷ ¥áøêžˆêÌÆÒÐ9.•2¦’î–7l Á©bÄÞ‹¿Ö<îÎ9ˆär¯Ó_ÆÞuÓ3ÉP-àÎ~/ñ5™©­ºðDès’­e\æW Ä!ÃšŠ¶Â™)Þþ„tÄ'x±Xðž°9ôÝ(½xùVÝ„¾¹íµbÛTJü?Í ×(U ëð¶65ìªlWM¤,eq¦ûèW™<“_3•Sxªn,XO °Zo㯭5ùK¦>·7¯¶æâf ô8ktj½Ø÷­ ^œšÄ›£´Àªj㊖ýr¾Š£]|lW:ucxnzÍ{Ú¾ÀÛ|x:Ô¡xZäqnR‘ÙËj$K˜° «L»>kAGWÌ5ïqêåÐd?3'eÍÃ1Ðëø%=K¹ÄÁLÛ¾ñü®‘n²+þ¼äGæ9ûÁ½Ê^ý­â¿¬i9¿Q!èÜ¿Eiî¶yDéÞ¯6ãJÒÛ{gÊ®7›’TóÌC›2GXà›À4@’k§¿[1oÎìû‡­§-!8wË$Bñú›D~jüy—udLů'—Cž³îvÔüI—Œ“nŸWé+eÉ ,z½’_äU;ojO„jâütØ}»Ê'÷¥äš9¦ß”¯¨:Y?ÉzÂÝ5—­{¡?EŸdÖk¦Šf¶Ã9}áÂù dy~sá @7Âvêì¹;å¸lú1£ÕÛ¾3Hƒ÷ߞƛ…°ü\]zž·ý.ý”(XkiØqØ\-(»îJýGéÅPäøÀþ/ð?!€#C Aõi>°+Âlcendstream endobj 211 0 obj << /Type /Font /Subtype /Type1 /Encoding 492 0 R /FirstChar 58 /LastChar 116 /Widths 493 0 R /BaseFont /ZVXWUP+CMSS8 /FontDescriptor 209 0 R >> endobj 209 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /ZVXWUP+CMSS8 /ItalicAngle 0 /StemV 87 /XHeight 444 /FontBBox [-65 -250 1062 761] /Flags 4 /CharSet (/colon/F/a/e/f/i/l/m/n/o/r/t) /FontFile 210 0 R >> endobj 493 0 obj [295 0 0 0 0 0 0 0 0 0 0 0 608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 510 0 0 0 472 325 0 0 253 0 0 253 844 549 531 0 0 363 0 384 ] endobj 492 0 obj << /Type /Encoding /Differences [ 0 /.notdef 58/colon 59/.notdef 70/F 71/.notdef 97/a 98/.notdef 101/e/f 103/.notdef 105/i 106/.notdef 108/l/m/n/o 112/.notdef 114/r 115/.notdef 116/t 117/.notdef] >> endobj 206 0 obj << /Length1 1419 /Length2 8046 /Length3 532 /Length 8907 /Filter /FlateDecode >> stream xÚí–U\ÛÛ¶¨q(VÜ%¸»+.Å¢B@`Š/.Žxq-îPŠK)Jq—"=YkŸ½Ú³Ïã½O÷w“—|cŽ9Ç7ÇüÏ$LtZº\26P+"ÔÆÅÇÍ÷ §®#àãæÅdb’saöPgy ô À'&Æñøy|ÂÏÄž ‰a2ä .>nö`;€UŽí¯$€ŒÈÍÞè PÂì@Nð5¬€.ÔÚóáÈ@ ¿f¸t@î 7O 7&ÀÆÞ°í1yþòQq¶…Dþ¶ñpù÷'ÈÍ.`…K²àŠ6PgˆÀd‹É£…×ÁMþoHýç⊈Ðé¯åá=ú_£@'{ˆÏC\<` 7€:ÔäæüŸ©† ©©ƒlì=œþsT„Ø[Ë8ƒ! ï¿BöîŠöÞ -{˜µÀqý9Ûü§¼m+ðh+ji)pü}šiíaz>.ÿ,úWîßÌ÷›á½q³÷˜ðróòòÁáï2ûR ÎÖP{gøã $ º¹}0áÏœ„¾|{g7ä ÷åáv†ÂàSð–øl¡n˜&?€ÇÖþ¯Øß(È àqºœ! [Øï(ßGÿu–ÿ„<ÖP''àïˆ0<~¾P›ß!;èn÷;" àyrƒþˆx Î X.óú=./³sý‘ñ—5ÔÃíw@à¯mxþ‘ws‡·ð‚3Èäü;wýýÁUíÿýkƒèïIÂðe¿gÃgÈýC"poÅHî¨ó›à‚º¿ n£ÿÁoÏïŠÁ‹Zý&xo¬ÿ!>^x ›?ÞÐ/þá²v ¼¨ý߿×püá?®áôùàÎ \úÂwîòÂ5ÜþÀ¿Nâ„kÀþ@¸†Ç¯ëõùá…|þÆÿ}ßde¡Þ¾\b.~øï…0@Dˆ×ÿ$Z{¸ÁŸbØß_eð[ûo¶µ‡ßqÈdùuj-þÆá]SXÙk…ÂÉrTvDYps¼F}÷LVÈB"¤øÓ WöÕ:£Ÿ„¸;¨;´^÷”îQí~ÚcŠÇA®ñis;ž–;¯Z)Î2Ô}¶]è¯CöŸ¶5Í^!jN¯Ž–% dŸ îçk±Êë}G_¦Cè1ñlèÉ|#,b¤˜Ñ­c ÓÁKs-‹ _ñÂKNDY™yíŽÑ±t m÷ øYˆ‘—ôhzM‡oÝN+ ³ÉN¤ó]ú ´(ïií¯þáêç™°®`uCç“JHaXuö+ ‹©Òq…uÏcÎÖv#º&a³Õâ-  »"Õ…÷¼'‰…ÐM>Ff¶©fˆZ),õ‰¿°ú™P40„$²…Mˆº‘ÛftNè£Þ’Ð’r1iQǰ(éVçø‘Q Õ·µ àDêNc›Û•µõi;;t‹a2¾2™3ܱxÌ'Üú¹NÔ⸙ͤÆ/×÷,“nÃD^¥¢a²ç72å–È<¢RÏ©òwŽé—Ú­XãgȹÜðsŽDdö–0Œ>'¾W-ÃÜuß#Z%å,›À‰¹T>dØ´I«»ÓpSeFÒÇ]È0`ºô‰¥z"±×SšfeüxòâI@ûƒ¢H+NÒî ¾¯†¯Ò›¤Všb^è’tñÑòZ•»: „Jöô,:y³o¤t Måõ¢öÃÁ@©âÆ%GA2šÑñÇ%ß½qqM¨è‹µl—ªcÎØ :‘h½ÒÆ¥ëÑÄà ‡÷¤ÊrñIbßL£ÏÛT¤Å#T©z-râZ F7ùÒ?dsJа¸P"ê@lû€¾)Dó§´øIXÔïz¼I†M(2ß=#§ø,.FF\©È–0$S7«\úü” &“'ëÄýÉ£#C©°Œïuc-øZ^w˜Ç‚éºqþjöbÙJ›e¾øî`ˆ]bê ÿ½^(•„c³Ù^”Mt€à¥+uÍ®ÜѦõ™IŸï’GRO¯1ÝÂÊ4NÇ3·u±vt0äÇ\½p_Fa¢Ò×6Þê,©G2>w·@†©ÎoÇ‘óÁ ,5 òù¢ O£·WâE‰™‰%»W%Ý4vŸø"ÛŠÈ^¼TçL×EÀT*‘Ì¿kX0Éú×ú¶ÉÞíÉK†Y#ïšõ& « íšìN™×Œ@V\IÓöø â_í„Ã9ßS,Úì P;ç¹]å¹P’!ŽõÚ…i”à]tѕȶIÚâ§ºŠ‹¤°®‹~Èá}´=ùu[äå{}w•t9+ƒŠnl%¼°{S®#–FòɆZñÞQsWkTÂ÷7䫲â‹L‡‹’£/Ø"$ÚˆÄzÎT#ýÐ4î×\Ÿ^xÙ#nNzù¶KÙ´Ê3`Ëî:M‡ÔÔ«o5Ù06_ö4fGK&æ®HYE¨&‡Kv@Šž'·dc®¼øú(‡ bT9Og¶­º•T6æ×à‰ R>‚ÞÇBçqFÙ_±x;Ç ³P^ò6ÛNâT»™ÝQˆú}¬]û“C”ð/”ü¯ÂBæÉügÆV)˜\V@PÝÌD×ÀKïÚ׊`ÛAÆÐﱓ_xÌË“¦ÍÎ4_Çç^ÙzÈz}ºs‘zw†>Þb ˜ÏA¯5Kêœö ðl­îÌ4$²#M9MaUìkA‡ÆÁÉgï¹oJÜk?F'FÞI"ÀW×b¹Ð°¦’ãît¯5º"²)—ׄbfÊ#m‰éõTf$Z¨§ÝÅc&\K_ŒpÍX¸…54<¥Y<ß[yH9ñÜË¡aLXúÞ£±¡c89 #uø‡pxf§µk¯ÐÓ}èÇHcv6+c™Ù8(Ìë %•Â…ÆØYdRLÈämHïÖÞÔf0½ãèµ?düù¶d:Â0úÇc/dYê¨!ÒŒ8ÿ¶^Ô\cz|ï 8͹•‰ÐßêÔt¼~,åá]ø¥ú5bË•x2tžê‚§Å*2m®6ü0ŸûVCRÚÏ[’˜=ÒïH4”½Êé ºà¶OAÊ©Š¤`9߇³Àm“ õ3¦ófÊ3O:àÛçFg”ýõ§@M¦C¿R¿ÕU÷lw *ÑŸ9ç3 i´DÏé+dŠÃúõ;Ë^¬§&Üc¨SV¾kÅjVÎ-S‹¼H}¯ÁdcKZtm5¬UÁÈp•½Þõ™O4…D8j!KOƒ3©žCÓÈÎ1ÇÖÆ³&¯:^=v²>=–aÙ|£ÚÔò©Ô‘D†_]¼Ÿ÷hUÜb%›b ;ÃбºRè‚HWÈXq̵K½¥½iW¢ø´ê‡L]Lÿ³þÕÎòû£,â‘þ9!Û\•çß“n;舩 _%‡xó†t+EžGÀŽŽåÇI@kÃ × 4;Óä!·µs…Ëfd:@s }ÎÌnv2æá͈K&]jim T×Êëe¡'1i´ìŒE{ìsK–ˆ¢Q5ôæßD§Z ¯a—êuÁ&èbŸŽH^ §„’hãâÊãúï/˜m#´ß³„KˆõŽ¿˜ô­QŠA ¹xoI%Þ¤½“«e‹«ù#_Êΰ.Þ$y÷¥‡W•?ãî› }žK¬¶M´ÖBÅìÇj)ÏÇÒGn´x,¬9$‚Ø7>y·ÃÓ–>PMFg!k,7M)"¨€.×·½<<Á˜#j:#'ɧ4É¦É `_Ê÷lGÇ‘æRçæÖ¼:6tdüÖìxVËññ^r !!›4zžÌ -Ù!ÌÂjV_' Íò]žÞšáÜòKèÄDsâOÖ1˜ázÔ (ötfIºDëðÔ¬)Ús\°ùj0ÔÂ8tz_½œ2XNÿìU<ÓCÌ&ECµÿÿB²TMòÑ‹u³ Ÿ!¹›Œ&ÚÕB2[²ò”Ä(¬ò²øJ$79²»ˆ‘‹Ý]ûbuצ†WñºñmCä‰&ï‰ z¼ecœ35›ÿ~7‚Ó—r©/8¡€n¦ã4µ’ö80m~õ§=D ªõEØ|7Iä­ºàÂCȘCe™…T28gyͧsÖ¹(Ë1Rµ!oš¡}^Ÿ1o IÈ^¸uÐaÝúš×$ÎóÛZ¿+TaÝt}Å/ÃS‚)¹û«¥{íÎÄ úõÊØ a†×ˉT»“åu¼u-óµ£1þ°Æg´xŸÃå¸b‚õ†¯ç†ŸÕ-SnÆû;'æ1u0`•è” xSúýê²mpM:ºƒ(Î¥þŒáÞi)ò}K…ŒŠsâCð¯_&œ†ä_ŒH¢?¢×í·µ%29ì_ãPl²®TvÙK'm¡pšLiÑEo æGmwU'‘P<…@HmÏÚ[Õ¢fSÖs}žÞƉ|$º^øˆ?ì™ê힂Ͳä½"†¨ÃázXµÆëåo íÛÜ^1:æüæX0{OŽôHIXÙ÷pñT­<^0Uå¦'L›ç×û®†³|ÙŽ“”dj? ’Zì ïçz¿2,ÌR‹4Ðögî¬mõ\é‚Ö±Uf OßÑܱY‘ÜØ f›p„g)í1¨}ƒÎÐѽý2‰„WTžTžyÓd96[põ±óeC—ÝE³ÖZrRlÌ; ëXÃOœ¹q/§P¹c„É[åú’#Â%2žYÍgPIQ³=^ä–©à¿.áê[¯ÊÒz¯·Í~eóµÖ]H6æ¹*:«u–=ÔßtãÁÃ|øÓ½zxIû"ê+†ö¤DdºO®ø¤ï¤E\êNìXÙIÒ×ëz‚¡-õIOÈž†<÷~Q›Ix|NÃ+¾ùz.c=w|²¿yLe#ôY§‹,`39ž<&aÐZl~œ`Hyu{hf²ÀQuHms¾H/FÂþ«Ã­I a-ÛÖêSÉĤ–RYfwHïÆÃ¦ò‚u)šÉ%?iNµµÈ*|çŒåƪ×ÂÝŒpwÃ?Ae~×JB³|qŸ²p~4æc˜aˆ¼X'¯½¾[#?Óðô±yêà3ɾ³ÞÅÖš‹=ºrjÕð˜ÓùÁ»xX/W›’]æk=5Èe;nÆ•¹÷17ÆQªà2gµÎ¼ôÆ4EåásOŽéUÍ}r6É›+˜µLÕü{™Ý5°{2ZqÊ$?U±xVͯì©'‹¼þ¥êfcÁG@‚ަϦ-|íÇã䋀Џën\Äo‰'‹QèŸ:˜ií‚7b„fÏ jeL^¾JÑiBì²M„‘54;,I¹+%ššŸìLsê8?’Ñ„!É³ß ‚ÏîÖÐr˜^l§4.É ò#Šô,wöìœÏ[¼oKéKOé">¾·z~@› aÍüÔÎ8ÃÜíŒOæ°£ôB ö>ùgpÊ"¢{láñq©˜öH¥ø9Ë·‘!W·° ÒÚD ¼Û¸XäÞ ‚,)ä"Ì=‘ë½@Á1{ª/zcèBÌD•ÊîJîDü] Ö¤#ì •6ÍÇ’3e7væW8Þ²qx”š¸d«DݯasÛ3 oü\å'–½i@GZŸS²öèQ¬ÑMêÙZ{õZ¥±‡HS®¹€÷i|©ç…,Ú7jÍ^Eq’T¯O”¼tÜ / YŒí5m,2•:oFQ®•aT§"çš´@ÆItªïl_Mצûž’+,ÖÙò+k?ŽyipQ £U¡i6ÞŽ ¥ÏåÓ–ÖŒ2ùF²A€€ñ]hè™›·}ò§ŒWIà  ˜¯%=w þ`pÓ´5 eÙ£É,à\b"ˆ“ôÖòeTNY{)°Îð<½߇¾;¿'7\x5åë*Ö}å5PPt¶Çðªb\¬¼4^ì]XÒNWã 2cùЮŽQé‡fK@Ô¹Óª*·bK··Ë[Ì<§˜«€²T®C 3ìÇN’¢×ºœTB§ÔLÄO½—ÖóLø*~È.ÙØ?NÙ#¸äÁx‘q爦ü㓘žN-°33m ‘ýãÂz¸ s:#œ¼D$À¡…í…ú$xË1¸g©VÑcìè$¯¡ƒŠ®Ðѯ¤#Æ—A““±ÉòQ¨…Þ |±Åƒš¥8`¬¨Ye`±Ö)çK@Ñdzt¼×h‰Že"„6ƒâ-ÊYu¿mù6Џ*‰˜( Ã¸Ž azèžm"kB¡@BûØpÔ0`äu%Q+OR«ÏedOÈ^JçUBy¥`˜•àNlþ¸ǃìàˬ)âÊK ȆŸ?ÙŠ‘°UŠ×òp¾ˆ"¾µº=Í“úµöG—žzóZb ãU4õÆÇ-Š5ΩreaõY1„'¤†ãºh ³í—ÓÙúj',=ïižÓÐ.xN¤EÉh7xèOsN÷þp¸~nÓÙN2·š^—ʼn%pV.ÇúZúu$‘ˆå¢ÏŽÔOËÕ<ó…9ñ0—bëé–“âd]6o&›.ñBNqnÎ_a“g†@R W’ú"‘7A¤‚Ô^ýç àñ>Å›k×T5ÄúŸ ÛtsQÞ1 +\:máÊ)>r÷ƤÖÌ[AN†“dØÄ+;ƧŽMC&Ü£ªÕ4F´î”AbJ cï—”EZ§Ä£õqÐ Y,N‰"ÔÈ7‘†Bº!'風]§ãljôèR"à) zååYyñ8[GßSpR,G3РÆø9¢T3ˆä¶Í¦Š­ÿ•ïc½<ñ¸Dv~x&ÔSÈ_€-Oaæ­ª– _¢~}t?g­í€˜£†,$™`¹Œ e‰E1TѽÁLå;‡±ÉS†ÒXzË‹Ö N¥¥û˜öùÃÌå˜4ÅÇ¡¡É©êâ Á”!­àV–¹UTF@#…}MáÈOl‹°™¬e{Šyºµ|rq)ÈIÏþ©@¸?÷Üaô:¸hbfçóøI+$ú¾C™U»Kî„ç‹ÃÁDûMÞ‘4Ö羪 ßf65§Õ”‚UófúŸ%Y™ÃS?G~ðËêÆîÔ² Po[¡ÏÕítÙ/‰²ÏY• ÈV´ê7êÆ!ä”dG)8”ô ØeÓ3«çZ¡ ¢C“£[>ïЮ9Ú@¹Õÿ!;/í¥/ &ƒïÀR“­š&–_~Õ:TŒ¿â2OÒˆ 2£l~b1ã?§ë)G‘³z„VU{s¾ÙLôã"ax9s§EHã}TJå; þ(ÕYm‡Ò×…y•…à&#s›ýÁ"ô) CÂTMQLoËÊá¢åÛÚyd±"°¡F§=îsž% å~ŠBÄHIŒ¶êHì2 ZaD¾%ç`× à2tÃÇ8½Žâu][ 'ÝÚsÍ»×—æ)&NF"e~6ˆÙ#=S¸5 6r¼’=FMŒÞ@¾€Z¯¤…xfCØþÌÚ¨ýöäDUÙòã3©G´3¡ãäÌ+\ßX`ÏûÚ§¥1ê¤øò‹L-©r#¹YÓ.” 㟋Œþ¬Žtc™%ŽÚ:l{-Xϲs8*d>û}áÁ ^í&ËG=ç&rÛÅL'æÙ™(ì\½YÂìÑEˆ—J,™Š!õ(ÄùúNcÚ+nnÄ)ô‡JpFc—0J¦?V£0_ÏR£’óüúôÆ5j暪WŽ RÏ7£e) ,| ¶ ª:ç¹h,bæó¦SEN–:=i­-uVÍcOpجè]7ê¸ RoÝŽ&zîL‹Õõ•¼ñº¼6q V|V·ÖÙoM!9F a»àÍþú–övq«Ñýþ{Ó(íÀÕ/+§‡¥Ä;2×¥ietÍ^+™ICyPdµLwØ šAYìpeV†äÛwçòº˜Ás2C™lâò!«yIam ¤^:ÎŽÈOöªÅÂ}+ Éäþ-ÄåInÂHq˜û¥uä– ÎñM›÷P–×W"öU¤./ªÃ¢S· ×·Fh~6ÉyšqRùò¶ÆÖÎ`|ñFÞ¯ƒï2Œ IÒsÈHÊÚÔîrS‚^Jþåé>¢ .‹ߪoî¡W“KDb ¾·Kü²¥½ÒóG“ dPbDmÝPûR¥3¦2Û\ÆS.Ð!nMÜR‰j“¬¶þ¢yÎÝFD0eGÖ{.j±r¦ýy™\¶ñ¾äûÌWÊU°´Ñ§˜Gßîm’ ü¦œÓ™(r IÝÂû)ùê.¹3Ù˜· Nz¿«¢÷éÑ~ÀÏ:ÁrK¯žN±/4Ɉ»$uŽ¿¦˜ršùP;@νoæŽÉ$¢4¬ÐO©‚÷oH[ß…gǧ‚XÞó)ìQ^‡±,»c{ærkˆÔ$qLz=gìmö¶cSçnóŽkgôÝlSFvÙÑÊÒñzBµŸJŧ¾ðù"팟š¹W#q¬4 âVHo‹ÉKÀÜýKY_w‡†ªÙ¯œ°Ú·œhV嵎YbØÕ’D?b(ÂjÈF±Tm2Ââ@T.wz»É7­i^À84׸OwÊ ƒ‰Üó<*˜k;šd:®Y«®‡Ï™R7Ûù£-ñkž^צ¤ÕË/Ù8bf°Å´†F(“Jld|ÉáUÐkç.JîÞ)IE ¯î>&i*äK½öðÄÕªH_16rþ¥”|¢oÓ7þyoåÞY/yGÙókàbè¥wªªÝzüøQziÁN¸L™Òbè’“îÎí Y‚!ýdv5ËÖhgqæ~2Ì$UJiåÌsõŒÆß;. ±ï‚Ê yÄD¤‘õ€\r ù2 «ÜÅßµ«§µ:µKMáÇ<0Ý<½…-ÊÆÊåR¯è­7K£‘ð5Ñð"LÊ  1¬‰9{ÙZ»hX`jVD±¾bAû’â'¹+Y’ñàGË,¬GèOлŏP8ð©ré¶1ã},(ÕÍ—…§RKT¬5ûpi»7,¦øt' $‹õásys•]Ò÷±L\AëÌ4¾}Z¥÷¹ÃÍ­,¬MÇÎHK'z¿]—óµ­ÿîK„U:E\œ]Îû÷„;¿¬ÊVø½«åài7Ó&2‡§å?-׫„J"7ÝX&MDøH“…£¯¢±&›R¸¢¤WkKvS®P¸–¼(X~ôÛ¤)~bÓɰ U9ÿuœ¢ïºuä$ãë”Çÿà èXUÃuk7 !#¤ ›ŽÜ¯×±w; ¢Ùü´Òú ¡Õ(Áù•‡ÐCv§±dØ”«»³`ú›õ7G_€o½V×(*ñE#ÆBŸ.Ý(Sr iŽ˜LdmRÈਣbæáy\Øö>™†å•}sPZ9å» þœc‰ îã6“Ûo0$6ã¾Úqh||–¶n4¼Q·õµDSpéöv†³êám¼Æ kÞ‡ÓS TB,;äl±å-šªzR»š­Õ½Ž5oc]‹Ñ\S%Îý×E§ÊÁqˆýF·6‘ßÖC»hAÈífÌv LM¸ß½õ?qú0§”­]cáX=“‘íÎò*)¼»ŸXOaõmIßö–!ÕW¢Xê]ËÉϘ\Ëùà"½Á$Ãf‡h­"—¯Ø&~®QÞÕW”NßËڭͥȂ±[zÞ¾9”qR»¡½ ¶cÌÄx™Ò$m:´ðBëíûÌ’'÷èž²7fTÆ¡«ñá\‘{õÃtɇsi-Ï™#¯„v©Í¼"”Œf‘ú”C»ôÃØŠï͉đÛé}Ä ÚØ„^çäŠö£­¹;û KQ»§¡Eؘõöµþ³¥]üæÏ?Û2jÊqÂѼÐm‰ò`zÐä¡Âœ›r,´W¬è¥ï.ˆH†èÎR /> endobj 205 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /QFNXPE+CMR9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-39 -250 1036 750] /Flags 4 /CharSet (/fi/parenleft/parenright/comma/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/at/C/F/R/S/U/a/b/c/d/e/g/h/i/j/k/l/m/n/o/p/r/s/t/u/w/y) /FontFile 206 0 R >> endobj 495 0 obj [571 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 400 400 0 0 285 0 285 514 514 514 514 514 514 514 514 514 514 514 285 0 0 0 0 0 799 0 0 742 0 0 671 0 0 0 0 0 0 0 0 0 0 0 756 571 0 771 0 0 0 0 0 0 0 0 0 0 0 514 571 457 571 457 0 514 571 285 314 542 285 856 571 514 571 0 402 405 400 571 0 742 0 542 ] endobj 494 0 obj << /Type /Encoding /Differences [ 0 /.notdef 12/fi 13/.notdef 40/parenleft/parenright 42/.notdef 44/comma 45/.notdef 46/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 64/at 65/.notdef 67/C 68/.notdef 70/F 71/.notdef 82/R/S 84/.notdef 85/U 86/.notdef 97/a/b/c/d/e 102/.notdef 103/g/h/i/j/k/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 119/w 120/.notdef 121/y 122/.notdef] >> endobj 202 0 obj << /Length1 771 /Length2 963 /Length3 532 /Length 1528 /Filter /FlateDecode >> stream xÚíR{8TiŽ’mªMWª§úÆe‘53grYíQFÌT”¢cÎgfÎáÌ™\KT”’.žHˆºz¶ÄSK‰.»’JR)º¨µZtÙCÛÓ³ús÷¯}ö|ÿœßï}¿÷{¿÷÷±=%æBŒ €.$A›#Ä8‰$«¬Â᱌Œœ(ˆÒ8I,Bih U2€ÏÚ–ØZX²Œ€ª¦pY LœL‡HÖ@¨€.E Bé ¨`4¤¨HH)i5år Ú¡b¨„T8Ä8,.¥A”á‹;dÈ$õ§6¦ ý …CJɘ&ŒISÀXÄHB® dq=Hæ,È8ù7LwQÉå¨bH~(¤¯`TËÕHE¨Š†‘¤ˆ‘ToøÉ›b¸J1u£Q9.29æˆ%‡g!øàJ<bž8- ¨\ ‡ûÀFZaÒ6ÂuŠ-s4û4ÕaÌÅ z¹:Þòp|©™Œ(<øò8<™õùo툳œ )‰á„ ðV¥(TÍâ1R|D"'0`c˜Ë!HšÙ˜d¢A I±††j¸¨’I W†03 ‡û\ •ɘ‡z__ÐÑ‘Œˆ4·æ6– bÁ·Ö ¬¢ÿÆ“ª( ôð bRú\âL²F@)«é6)µÛ¼ÿlbaŒóảZÜqý×N±¢íͲ[s–Ôö•h+Ÿh4­ÓŒJ¸ê½ŸÒpvÞŽè†Ã„o ‡ý{)L´3\lµÜ7Eº²+r†ßn{µ–ÎË7¯6u‹ƒ7?->ýûÉi,ß¶[3o«ËÂój‹’ ‹+¹ZÄ€©ËÁæT½£—s*ª6®YUQ8X«×v&j…‡^ËV³vçܨ\Òq[VVÏ|Üw•_º-ì…®úëMîmöw©²wµH±-«œÿ)~\v–·"†šæu2fN•2Ôí*Üñ³è¦?¬ìw +ýjkŠÊ¿í¢âÍB½yH¸0£ùYcgÉ䘜ö1¬ÈåÇO´œÛaÊ[R+$jžíJe'h*]ž(õݯû«ŽvË Ju¨cì$Ó©¾q=׎ìMbR9ºûmctziðü­ w[ž‚£¸/Ž·ÇWÞ\>9zíáh<¯YW˜™Ö¹wí9É5×:Ÿoq~нþ…ë_¾›X`­¼á›[’U9‘Æ+ êJ¶$!Zæp$íîìDüDXØ£çæn<¶´ñú },Öf”Í­r}HÊ“;D-gh öˆ: Ò².®2{qçò+õ®šé=eSrºÏŸôUT®é7l¨ê Ðqß”Ø5©¼ÿØ|ÕÝœ¨|—¥ÂØž–éÆ+èã3§ùÓÙ6ÅqšvƒE‘aû¢ÇŒrwoõ*µå†nW{óþáÇú_à?! •C”¢IJ…°þƒ¤;endstream endobj 203 0 obj << /Type /Font /Subtype /Type1 /Encoding 496 0 R /FirstChar 3 /LastChar 121 /Widths 497 0 R /BaseFont /BAMDOB+CMSY6 /FontDescriptor 201 0 R >> endobj 201 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /BAMDOB+CMSY6 /ItalicAngle -14.035 /StemV 93 /XHeight 431 /FontBBox [-4 -948 1329 786] /Flags 4 /CharSet (/asteriskmath/dagger) /FontFile 202 0 R >> endobj 497 0 obj [639 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 574 ] endobj 496 0 obj << /Type /Encoding /Differences [ 0 /.notdef 3/asteriskmath 4/.notdef 121/dagger 122/.notdef] >> endobj 199 0 obj << /Length1 1516 /Length2 6486 /Length3 532 /Length 7369 /Filter /FlateDecode >> stream xÚí”e\”}·ïAºKº†n:éîn††˜!†PéA¤AR”%¤KJéNiÉ3÷ýìç†óì—ç¼ÚŸ=×›ù®µþkýÖZÿëbaÐÒ呱…Ù€`P8?/¿@V]W—àçb³°Èºƒ­áTΖð‹‹ód<í¿¨„  „ 6 @æêë±w€Øe9þ ȸ€Ý! k(@ÝîvAäY;ta îË qvèüu ö»{my±ùù¶`¶‡@±ùþR¤ µƒDÿe¶õtý·Ë ìî`Gˆä $Ú ξ[°6Ÿ Q ŒPòÿCÔ&WðtvÖ°vù+ýßSúo~kˆ³ïEÀ\\=á`w€:ÌìýÏPCð¿Ä©ƒm!ž.ÿéU†[;C@2P{g0ø/ÄCâ¶Õ‚ÀA;kgðßv0Ôö?E ÷·>¹çªª&Z\ÿµÑ¿ZÖ(\Ï×õŸ´EÿÍü÷Œ˜;Ä` äùˆçßÿÌÿ£˜<³…@WBX`íîn틸øñ P[°ìƒPÌÇ …ÁGˆ¡ì`îØ-±s>»¿m£€sq±¾·ø|]ÀÐ{“€Ï±I˜í½I À÷ì»7ˆø`Pð?, ðÁ½ïýˆºpwðƒ„˜§û½Aa€x=ˆ@ˆó@ŒåFHó{=P†ß¿ÖúEÀ…<"‚8$sOˆÏï ,{Oˆžäî Ñü?$ŠhGážJ•ï ‘SížY4î ‘EóCdѺ'Ätî ‘S÷ž­ëÝ¢ý{B¨6ü‡¯ßýöÄÕmî Qôñåm b%àø×> BÃDH€<@Dçˆ(ärˆ»Ï}€ˆB°ˆ(äú»=@D]÷ø×Î bÖðˆhÞó"Ty=@„*ï{@Èð}€/þÆÿþ6?óñãáð .²8bŽ¢ÂâÿWÈÓÝ …ÿý¥D|þÍvÄ öƒ°g~À@OBS¾„}|)Ÿ?ò ù¹}]‚FMÛx3Nðôdç¢~U7ÎÅj£Ë’tüM´Mzïkj¨&íï ‡n ©“·›^V›é/¨ŽÓÕ}7\σw ¾~™8ÝFÖ[øøÖ¸ ;ë¨g7W‹]No cž©ÝÔ«¶=#DDÔH!ÝY?<´šUA‡0Õíc„Pø‚7áÛDÔ…áà—Žá˜õ\s¿`MžÄ—ù˜ï“nÍÎIã‰@ÍC;±µâsÛµ}£©mbðÏ›W§‰ðG®ÎM´EÝšªçò„Û‰rìF?2WΡêœÃ¿ ªoEèôªbÞè×CMHÉ™ÃÊóGž×OgÆà§ n,=Q€ùÕwôì«ÍÞé_»Hmbµ¶—J@í/¾^ð„5nk‘•Ù\WêÙcróšŒ+ÉÊfrŸé'lø¿_T¢z!´•Æ_¥ýT Hjí*®Z¯0A<:{5ŽÁø‹§)w°§¶©#½rìòžn|#‰SÐêŠ/R5;ß/ÆC<Å:ljmõ%Tá}¦˜ÇÍ¿]òd‰^µœ‹Ç§ì&{cìƒz|_6R+ìP–TÍ6çºÕ}×"0·¸Zÿ3йé(ô<à©:®,!{RàŸÖjÍS:‰Hg©>~´Šðg\'/Q«Ku$t šò¬¯}vÇì‘Ñ>…ù¢¼"×,‘+EôA›U¡áƒq•"Ò®Xv÷÷á'X ½¶'“íäÄBös249<0£A×ö5.o7`еšæD÷÷54Ë´8wù„¸ýÍeƒ";ÞÍ1 L ß»‘:UIö#e"Kv™á¨¶Ì?°é´(Ké+É[‰÷ß .ë+£±m?¶Ußò{^‹Ýuqfâ~%ùˆ™“Úº¢¡D аX}Ã6€Y)_òènÐÚo7—ikþÐcÿU÷ŒnSqƆÕè:*`i8HÞºš‡¤ëò›¸KžÂèĈ$V;›†­Á]¦;·ó%52º¨À¤Q»“@¾ESKü®‹_L¢Þ’"‚Ü"’øÌ™àÇå|U×qõ AŸIYHª•ÚU¿äÝG=7¿ ™`Áwè ü‰™Æù“[´¶îÈš{—fN>«oŠIÜa™–%×t sãÇJ£/¼FÀ”ô˜\[®Æ´éUSõÈv~M@žaVÙt¯RÞÌ7 ò…õDÎ)çJx?™Î9…ìÚ ç¥ï‘Ù¾ΆOõ”j…íOŒ b õ`³ ÕOÈ{ã›2ïl3†¥§"=B%ašV¬‘d×èÈ—çÆb.ø¡€TeÖºkÿþƒ¿ s,NÅ\"}`VË,Ýõd?O@ãDkî¦ü[ù¾IO›¥;ÚÝ©ú-k)ÏaþIÔ¥6R8QãBªOÐÍ©Fzž…Å꤉a@\¯I%Hý2í­Þ´ÿ¯ä^ç( RW*?c뛼¬Ê­¼|bößB7FÖ†i ==—üsLÞ]¥Ó‘SS±¹åå‘5wšf`z«€nlo»‡Ôµ»°zu…‡èÄÖ-ÄÕÑ TgdñÞ„V ø‰ÛOÖ&»>ð!t®:xhüeïÄ‚¥€·j‹¥s„×Ö!hMÚ“ÛŒy\kFãÓÌJ¸á½Å˜‰™qäe|·ÁºNûâØ,·ì¿£N¥ë68î0e:p2ÖW¹[o0P‡Ä? ú.ë4ç n¢V󸽃ý†šKѨø&4õÇSdѱ¢Ãël¹ÒW0A/QmÊŽ~ù5©uÇÒ¿ü¶b_ QÁSe^‹Ãçà2ŸL–Jçå0¬œmA^óÊé§JøÖ¾,ÍTÇAdf1ÐáN~&Å‹ÀôÐ]}ë¹ìåbfÂ=ãc_¶NäÛÙ{^<,ç´xkŽi¢Ùrwgïró'ñ±GIÒ,¡|¬Y¦ÊØÒ‰•N='jÖXN¹tb¥6–{/~è‚@’ìX—Y•¦K÷«¶XZÈïÞœô`ÐÏÖlaËRËþ /":_!4ËçSôó¦$Mr›žÃ‹Õ•þ§¢gòO–ÞfÒA~5i˜Ái˜ekŽáÏ¢£U7e€{\ 2¡[Ò'ýêÔÁò ç»((ÄÆV¿_;MIAòÈÖ~%ôŒùýZUžè›ïµ®>kÄA’ÈôÃÌ$ôÈ[0=+V}®“³Íœ&»ùýóª¢è*•6–H™–…ƒú«T寇¯—pNl§‹ë_‘xÈÌÌ«co®°'ú ¬—ÌÓ ^8g}Öž2£ó68%›[±m¸ÒFþ9ÿü”÷¢àªÝ5ç`pØw9:ü>n?úåð$/ÔÇ­x"r­[Yž•~¼8ª)¬Šœíêh?¾(cFr|ùs0ºó²Lùðë£ÓÞ¹w Š9.TÒ3ÔUQ«W²$·Ë;ʺ,[Ô¹Jv~mIŸ®zÇi>øÑ—ì®Rë¹ÀV‚P%iÖùC£Â_.lZ„¨â\ÄNOhÐf"+tÓrr&ªôŸFÏ÷5ïŸgC>ì¡<ÝRR#k¸ 3¢>ž"—ýß·-&•ð´¤72‰¡Vý%©ùÝûŒºhë9©hôQ dåçJ°@Á× :ŽvÁýÑ#ŽGçºÃó‘ž'.…‚í9x]|Ñç'êŽRò  ×]øtòSÆ‹¡é¯Ð.í{D•8NÖuý´ynÜÆúþËCÆH£#ZÙ¸ccfåm£ÿœI::çúlń͋rXC•ÖÝãîC}¤Fâ]NÁ§° '¹WÐÈ¥-s´_DrËþ±É|Äy¿üÅÊcú/!ß ¬PÐŒWGß,×Dv„è[œOcüÀ²uNé/üß{[,¿ºï$*ÚÑ5‡›ÍU×)Ÿ5xFÆÖW1—f )YÀ_{5÷däá€;íÄo¢˜¾ Œ˜ÞÙgX5ÕšÈ|âÍ­¯E¢´¾Pý±]äˆ3fçešÒ v±B.w€±ó'-wIË/˜Ô)WvUØÌLú‡‹­–BÜ|˜t«ä<ƒéBßBˆˆïò”²á!Ïp;Y‰°.Q’]Ÿh4òÍ×ô÷ý.übÿƈ ÝXÕ⟈uÕ%þlLšüF;!ù»ðú…EÖè}‰Ò³ößßï^{Wê?V¬g>§x³¥H›n^ů6L`‹}«*ë‰ÑÚª5ù~¾ŠImæCi ˆ §ó•fáÏ\óá³BÑ€…0Šï‘Ì{Jâ©1›öjA‡äÒAn¼éœ…zQï„ðñ½"ç´ò"ؼPB7’Ò2¬©†¦e-äoO‰l$ûìºdhšëúÛS†±Í™2ðÊXÕ1Ö“7S\€:_–:D>Ó³°ñ [m{ÈP‹€ žÖTæ×¥êkj¦I7ØJ7’TÁÒq­Aî%‡¤¦&5h'Ö³¾ï³oyRÜÉ$߬U« ÇÝŠÎFØ<˜D¨B‡¬ÀU¨q’Xt•g¹ÂÂN BÕžŒö±Ô‘s%÷I<ß‹c3e—°RpǘÊÏîwâ'xþß&-ìwð(­>È3Ôª2ßÇü$\ÁËõ/˜ÖÀ«'q>L6ìO&ç£×‹h솯û?=>‘Ð$‡Zbû§Šç%sž1êUé’±E)Û*Z t GˆÒÛVVŽ)*ÙaÇJø³vb_såͯk†¾Ÿ;Õõ.ÿæ AÖ 4œ°º¡l#¢Ïgö[wš%šEê³#tPõÍ«Ò4S1ŠîNÛJy]î‰0zÐ`Oî6Ä0ÿkä2¾…­!NäÊž·пü3ãs'Ÿªí)JhVCŠhV-³PÇc²÷Ë&¡ÚÖÂÑE÷‰z¸mà´c?ÁkÁ ‰V3&«gBÉôbÌ@$î^΃ÏÀýË‚ÞO$ÅP™,¢€=2_¡o‰rÉ—„Z²dó0Ÿ€Ž?ß1êÚEþØkH<©î,EÚ]÷žÖñûÂÍZTlÙlNTx(sCzÙ«è&·—¢t ÏN†]p«ÄNË0YØÚ<²°–V'6nvbyöj?4=ù#ˆÍà€¾]Î,ïæ|½MãlÀ]-èçGû€½™w‚_©næBL\Ÿˆµ ¥`6êxq»~¹>Î(Äíh0}žÔϧÌÞÁ8”*ľÕ2²¾:%ýöVé¸"ÉLÍÃÜtºe—X#–¸r,Ìq¦áÊñî˜Ää¼Qш׈ëž~‚§ØîÎ21yãX~;7ï‘:TûúlѨÑ×+ü„9ìFg5G¥Uâóó#µë“e“GðW‡?ê·ŠòÚ€©:\¨;9 8ëDÇ/þãÅ]Øõ¾©7Üö6öýÓY|h_@Å ™„vyæ"[Ö¾Ö­¡c9eõM•÷™ ´—Î'†ß Í“`#Ne¦6¯œqw³"áÍÐú¥%ÛãÀŠâ”ÓyM‘ÚMÕΘ~—øâç£*Ê e—è2EOrΤ)b'ì?éUy{T…@4ONËÿð6mxöe¡û¿«¼ê¿DÕ“02ó[w9â «È·¸ãRa)_{ýL4šÑ]b@oÎ÷×¹Ug^Ñ Â7 Þ•‰hDiš ¥;ì¾í6QAÊAiøæXZnãi²8†‚4M§n?8{·-"¯¥NúíË-¦J¼eK߃´ü–iÕeÆ‚¿çøçcuJ2T´™ï"§ò½ŠîöÛ{4CW|¡x¸Xª î‘`ÊãÝ>Œö2Ó¹&ÛßBÁ´öפ‹*MPrXÏ äœl“ø³bȬGßFHV÷Èäýè­ÌÎlòñ–ç$§x~ÊÞölÃâ@¿Û@:2˜4ǰåJ¡=BF\OÒØæ܇ñˆ¶ýÀæ™–þàtRÕ’!À@`ò®›ŒBLIÔ%#ûyÝ0ÛךÉ主ÖìÑ.ž…‰/™Foi^m¶@#œØ`‚é˜ø)/OòªX2%2Ëê“R+æ¼éRW¸ÇM¾P­ i‹ j©ì÷•ŠÇ2ëÆ\röžÝoƳa=ECwZV§íå@þéqé£jc…³zƒÁ2äœm˜Á•“yŸ_ît”ÉS!&´Ô÷°$†—‹\Ýml´G¦7±hÜ‘HŸ#ÛÕš²=räŒA’Ãê’¾ËPˆ8Ÿÿ›Ç×{lþúXõ|X¾j'¥ÐOB·>š{[$ªAÂôŽ&‚îA£ÓùkUžÐš¯Ò®D²KFUía¤Nï¾z­¡ éËbËlÉü~•÷Ûã¸=ð0×|…Y©êÂëÏçŸ,ÒÃëOj² ºC ݨ‹ùE#†/ÞR±…çᛊÇ0W±8ÇÎ˳wí“‹—Ç:ÌèÞq_ (8ÜV`J±w~¯\9"hhã“]„[,šà”xyŠ:U€Ð7¸© c°«>}jŽÐ›U¶ð®;ÿ>§KHih@î&Õ_?=×òÃ'­5N £÷âĦp"ds˜Ÿ{\òÞu¥óV™½(v=ÿEr»ç»×ŠD¬ÐÜ/˜™:¾´ÉÌ›9¢rï.-™”BGïeÍnÞê[>â­¥±xb1nÇü¯Ž•¶MÎ>˜ÙjlgÕY®BÊ]U:çU—c«Ëõ(§˜_f±©¾eSE«ÓÙZ¶T­½0h" vdxªW§"pýŸ­¢*áfø B&𓽠g•A²DÊ¢Ãϔ۷ï“ÜãŒ^Ë?{OóD6!³ QW®rÌMCÙr888 Yr,Ñ" õ1“MˆÃÃí§*Þ~œeD܇¼†2«`â(S½%NÛѪ0ÁF­º¿U†ÚýH´•Õ)«Ã£ãMžcˆ¦ÓEqÿމŽÂàX[(0M͹ßÝ«€¦àsœÈWÍ”K/Ù`2Tp¡ž†’»üZ é"r­mkX(é åÚb˜“ugÉòj*_žZ÷ï1~ÒÅÀB^N¿´\µ á8KعŠ`@qFugßFÊ‚&¼n¡Ó:\:o˜)¥ÞæïÝ›¼4®^ù»6­6oAétOœÍÎ1öðÙ'ò[ä§,T©z­ùñ, 8:Š \V`sÆJ:CòŠÿÛ”Ô±â?Ö—Eµ˜{•íÃTîôZŽü^ÚÉó‚—âr«»…d8l™ë’¥$¼C/S¥˜*>””ùÞÚÕ ¨ñ·zä³”Üu†ªa¨³0ÂvÝë/ý슺XþìѦ|«¨gà«j©Q†z L¢škÛ@4ò°cM!ŠMBL×}5€,ÿз( ~ÐÜdï~||ò»OoÏßö¨>nå}o%wÌãs}ÂǨx¶•Ÿˆ³zÞW¸aiM9Q)B¯ºû1@/Y Nhèíß8(¾GòŒ|Ê)!‹g½þæî£ñçŸúfÛ˜Z„6ìK#DŠì,¨‚ñµh‘¼%ç"1󛳉o”ù+µóï }4yhm!VmÐAžJ‹¤½ ø$öÕ-ë]JÇÀ< %ý¸‘›¾ãp ÌÖŸz|ó3^íêÖ!¥ÅIÅ£ ÃGþ[2¹¿q/Wž³R¯#æ{ÝìEHÇôK²_mÞâ?Ò ±xÉ0$ëZ …[âÔ‚ü¨uÜÊÌÿôÌe'|ßçy)›NC|¤w&™V”˜*’Ç£r[’|—îeëÕ}G³A£XÁØÛòR‚t„ú…~Šõñiçõ¥!Èq;0=x¬ìvqîcî£#d?’s÷]&e¬¥,›?ìíiŽC ŽYq±9FÊ–Ån}Ð,v›Þ†p*Ûï3œ‘ú£ÄŸ}æðYpCÕ5rÝx|º‚?ìí»¹¿®}u÷3TÍÞUÒh‰õr4Eo,²€ÄZGë,!³ñi4Œ™R¨/cÝïþãO1­š˜ÖFF³„γ |r®øáž*Ïæµ%p@\™=més•°Å Nͧ„ÛäoÈ_t‰t#[Þ zzmáý,~Lc¡½U9ÞˆùYò£´ñm޲ë+\ÔÞõ³½t°®øR¾ÍùÏ« ¾­PQZ®Ò‡ÚÊ·J†G¿\˜÷~ü¸AÕIѪ¾6¼…œÆAE{3“|»ú¨H¾]&UVÑýÎf1kÍmY¿byu7Θãf OA9°“ x÷HýàÝ$¹Õp!A^G¡{…SßîGç›JÎ\‰« Èm\ùceQÅÆ Ý\ù¼H>ošºpÎ÷‚¦µÁøÿøÃþßÿ#€œÁÖîp˜‹µ»öÿøãœendstream endobj 200 0 obj << /Type /Font /Subtype /Type1 /Encoding 498 0 R /FirstChar 11 /LastChar 122 /Widths 499 0 R /BaseFont /DBKKZP+CMSS10 /FontDescriptor 198 0 R >> endobj 198 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /DBKKZP+CMSS10 /ItalicAngle 0 /StemV 78 /XHeight 444 /FontBBox [-61 -250 999 759] /Flags 4 /CharSet (/ff/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/A/B/C/D/E/F/I/L/N/O/P/R/S/T/U/W/a/b/c/d/e/f/h/i/l/m/n/o/p/q/r/s/t/u/v/w/y/z) /FontFile 199 0 R >> endobj 499 0 obj [583 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 333 278 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 667 667 639 722 597 569 0 0 278 0 0 542 0 708 736 639 0 646 556 681 688 0 944 0 0 0 0 0 0 0 0 0 481 517 444 517 444 306 0 517 239 0 0 239 794 517 500 517 517 342 383 361 517 461 683 0 461 435 ] endobj 498 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 44/comma/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine 58/.notdef 65/A/B/C/D/E/F 71/.notdef 73/I 74/.notdef 76/L 77/.notdef 78/N/O/P 81/.notdef 82/R/S/T/U 86/.notdef 87/W 88/.notdef 97/a/b/c/d/e/f 103/.notdef 104/h/i 106/.notdef 108/l/m/n/o/p/q/r/s/t/u/v/w 120/.notdef 121/y/z 123/.notdef] >> endobj 195 0 obj << /Length1 846 /Length2 1891 /Length3 532 /Length 2487 /Filter /FlateDecode >> stream xÚíR{<”ù6n1¨HI‡¼’]—˜̨ёÁ`DalÊe5fÞa3Ì¥fr™²Í •(Õ©u¯ãZ™¢E®ÝÖ­\FäE¹¤bvq&¶=íŸçüu>çýýó>ßïó{¾Ïçùþ õ=ðf=t¢ÓXfsppÇãq a‡:0@‹B§9X @ìØ0ì`À ¬Ñ–Vh$j8Ð#¸ Jp 0r0þD²0á ƒB$Ðw+ —j TO'R@×ÀP©€×§LÀ d‚ŒC ÉŠ@$ ‘ÁöÉŽF¦ÖŸË$vÄ—Ö!Á”šŒ¤&©EFå$ …í¡KgR'ÿ Sߊ;±©Ô=„ðOòŸcú N¡rÿE¡‡G°Y p§“@í[ªøÙ;H¢°Ã¿íâX*…ˆ¡SAÀLºŽ•"…éDá€$ ‹ T&¸Ri¤omH³[1ór±wñ8`úe«+]…ÆòæF€ü+}#¾biF ðƒ›Ãá)Qz¾ü|3 K#ÒIšôY QÁ p¡Ò÷!EH Ph$€©e˜9Î’^¤¹Äd:úi©Ö(æö©ôm`{þ@Ò­Á_‘´ôBHÝÀÀ¯`´?A$cþ J§°Và_£²·§s¢Ì¤êfH„TiX#·Çü‘Èf0@kå)Jÿ‚Éé‚@¡âN:Ñæxè…rAA,6«õº‚1SG˜wüIÿ–ÐÆ|â…Æ3†¨ÅÜ<«ÎW¥ÜX{þÍîB‰ŒÐ.ÇD7Eáaünõ&5Mãk—𫦈þ?Ê>Èl¬]ž‘8&Ö‰™Nõ¼ï?T¥Pìö aý³ö›ò]‹ïbÃx¿ˆU.’ FÏC2+ÝÒÀ}ãýgK&éYtqÎ-ÿKï×-‰µkûÚÃzÕ„;’2Ýå:ó§ýœ‹†ÑO.Í®ße‰y¹×É÷ÍnI1•íZãn]Y] ‰Þzz:Ž÷NAW>¹¥Ë>Ûó$Z\“Ô»Ö¨éO»¥ØÝû®ßÍÛ‡;¸µÁ÷n~¸ä9¾ ËÙ'ùëE±bŒ9¥ƒMç¶'χì·4Ù¼úã}f~»–cúr¼ÑWaZ¥•£¾*ªç »ÊE_0'rª;µ»¢Ö0F-Äñ¦.F.û~6sóKÚ…˜™ÛiNUOýa"™}¡t—QjZuæH ÜU½8Ô³r¹¡xHN±öhW÷†Ã£’¤G×Ó_í6H‚9YM¸’0™‡..ò*‰“GloHr{½2ÝÇ"[¦JºA9!=bŸ÷ÃÞþî²}v©Gó:Qé)ÃV7J~=’ñ,?.ýulVþÕר½k22&~.ñX[ïöáºP2ÇÏMüä6(!š—*Ö.46…¤X–£®¤]:Y•mûÎÇ óv&Uòè2…ÓœR‚„¥µ¸cÌfÑ"'e:·hD1×ÙÓM¢S——¡XX(U{ uÈM<—±?‘ø1sñu¶ìî+$qoÒIý1T©ãÏ‹ì[W†Ú˜Œ ÅkÂÍÞ‚èØžŠù§ñ[0ƒ’—CY2¡>ËÔã6a:²ý®âÑé¾jV OU?ð;ú‡NÒo>ÂvpµíðŪ·éó÷½õi“èëMxëš–—Z:Þ³ ƒ>G»ú^ü6 Ã‰¿.¹£gg×ïã©÷#Lƒ·Ã½|Ëìøzù¾ø”ùáS{ê’ýÈú¥ü [ï=§Bdгŧ¼±U1ªª:%3¤à9®y3tÄSüqÓ;­åfFvhˆv«f™UIÙM³ôù3Ù-Ìmo5&ÆÃ*_ÙèÛ:ùT¨¡Æü³8wêåúíÚ#`5+À ~ëÑøûxª?¦ülñÓèÓE2ÇÍ8I|^òu>澉“ü¹WCwÂí,W¿S^U­'ج©è2…x ¯¯S×>¾Õ…}óîÕœá²Ç £‘_#¼Z‡wŠ÷ 9 ÑÛŽ×i/Æ Åu¨Åõ,¡Fº1=œœùóøÃUOµ6Ÿ´ ò”bäØÙ»ûâ]l îÒíwbÇuuqvLùAÂ>ÞB‡Ñ‘·êWçÉ)¡¡jÞ/r~Ë­ä¡a¾ÿXs¿) ;?Œ ߃»Ó-RɶljÍC6Pë6ìJŒ´»[ƒ2÷Ék¿wŒÌXB´2YÈÖž®emÎìŒ|¦‡ª¬ÑLØ>§rËè{Œþ¦™TȪ 9€ î­¢ìz¿B{^è1Õ;9µm¸èùäHÜœöøPúý@Mü˜â¶K/÷Ëf¥*-¢¨a‘À¤BX2¸¤èé¥õ XŽÚ6r,±ÖÞ`¿•¨®%kr?·³óáYÍÆÓNd‡ŸçôªMù“÷d]°è¡ÆãÅÌä¾ %ž2ì¦@Çv׺¢õÍò:ÈG <—©i4 Ë­\F‰ìù/-¡ºðÿðƒþ_àB€H =œÀƒþ Ù3endstream endobj 196 0 obj << /Type /Font /Subtype /Type1 /Encoding 500 0 R /FirstChar 76 /LastChar 116 /Widths 501 0 R /BaseFont /RHBHPY+CMSSI12 /FontDescriptor 194 0 R >> endobj 194 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /RHBHPY+CMSSI12 /ItalicAngle -12 /StemV 78 /XHeight 444 /FontBBox [-98 -251 1052 758] /Flags 4 /CharSet (/L/N/a/b/e/n/s/t) /FontFile 195 0 R >> endobj 501 0 obj [529 0 686 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 469 502 0 0 435 0 0 0 0 0 0 0 0 502 0 0 0 0 375 354 ] endobj 500 0 obj << /Type /Encoding /Differences [ 0 /.notdef 76/L 77/.notdef 78/N 79/.notdef 97/a/b 99/.notdef 101/e 102/.notdef 110/n 111/.notdef 115/s/t 117/.notdef] >> endobj 192 0 obj << /Length1 772 /Length2 944 /Length3 532 /Length 1505 /Filter /FlateDecode >> stream xÚíR{8Ti®<‹Fé¢è©‘Kfæ`L¨„’É3)B»Ç9Ÿ™£™3œ9.ó´¬Ý [ŠHn]h»ª©´]´1mYʺ š¨‡R¶T{h{zVîþµÏžïŸóû½ï÷þÞóþ޹‰ŸÈÖ —‡AO9IÛ"lÄxøˆ‚æ„Íe™›{P¥ 9¹¥¡3@œœà-pùÎvvÎCòH%Eˆ%4°ô°"ñ› R†’À¥%PÆh`¨ˆäi%¸I¥@8tC„P©ˆ³Yp£A$‹3dH@†ËÿcŽüÅ@JÁ˜–ŒI+ÀXÄå¤T pÎâøÊ™Yqòo˜)î-•ú¢²!ù¡¾€Q!UþEË"£iH9)r$u5üèÍâD´l$* Q)¹‘b)¶ˆ›kÏû O"â~I@8*UÀá>$ñ‘V˜ô†p– ƒüüWÛ|Üê0æ‡$½R ÷3y¸F>×LF‚¹l.aˆÌùô:bÖR“ã)vÞ徦èüëÖÛzÖÂLkS#¾ú€NËèi†Ê–ÎÆAc“±òƒ…÷ÏZgš‘Z¬¯ñ¸} =lÖ°4½Î+‹Ò6qhZ^­?:¹T5;±¿E]oZ~ì{‹ý0 Y>g¦Ê®öÝ€£ö™CŽu¦Äö ÐIjúcŽôQíd§;G+ñf–¥Wäs³·w §Õ­`Ï»ÞØ«#c™¬a_SX›€?!ÍA»ýÖM¯ËÖÞ§›[nÅÚ|RRµ>d’q±ºA5/WwåŒ:åTÕ‰ïÒÍ) \’.èZ–aébÑñá­¨öÕ×ñ»CÏêÇt;¥D%íOÕæuÝ=T¥7®šñ¼$YŠa7»•ÞïŠWp,‚¦ÃuÆ­Ó¶Ö׸t>•ªš6N{Þ!)»Ø¶÷2r%¥[o··÷-Îù¹SŸŒÊÚ{4?¦*à䨲óV™…gׇòž:‹“{¾ýµ¿(¬†[n-‘ÖŒÍÉ3ݘ9:C÷òx-óÒC¡¸õæÎi©Ï\Èè'†µ|ffŸ{¡ºø‡Ëw¼ïöˆØæ±]R´O“”¢ño®çþÇõ¿ÀB“B”¢å2”ZÇúUP9{endstream endobj 193 0 obj << /Type /Font /Subtype /Type1 /Encoding 502 0 R /FirstChar 3 /LastChar 121 /Widths 503 0 R /BaseFont /GRYPQW+CMSY8 /FontDescriptor 191 0 R >> endobj 191 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /GRYPQW+CMSY8 /ItalicAngle -14.035 /StemV 89 /XHeight 431 /FontBBox [-30 -955 1185 779] /Flags 4 /CharSet (/asteriskmath/dagger) /FontFile 192 0 R >> endobj 503 0 obj [531 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 472 ] endobj 502 0 obj << /Type /Encoding /Differences [ 0 /.notdef 3/asteriskmath 4/.notdef 121/dagger 122/.notdef] >> endobj 188 0 obj << /Length1 1071 /Length2 3546 /Length3 532 /Length 4246 /Filter /FlateDecode >> stream xÚí“y<”mÛÇ­a,Iöõ"û63–l‘%D ²EÆLfa[ö-R–ÈÊ’$’5Œ%*…ì{YвFïÔýÜ÷í½Ÿ?ß÷¯çó\×?×÷8óøýÎã<.)qK+%7œ+Ò‡%*A•¡Ú€Ñ9++¨ U†€¤¤ŒðH8…Þ‚‘ÚTK <ÕÐVUÕVÓIF8ï<ÊÓÈÉýJÒ 0H< ÇçàDO$†ZGV8 I P Ðhök€! H¼/ÒM…n(pEz ° ð/GfXw ñGØäýç’/O šd©&åªE7¸!ÝAàó8ª’êäÿÃÔ?‹›Ðèóp̯ò¿»ôoëp ð¯ Æ›DDâs87$ûÏT[äæÎ!ÝP$Ì?W͈p4 a€õ@#È!Áåt³Dž€;M@þŽ#±nÿ4AmÜo `#+˜±éi…ÝèïEK8 K´ðþ«ì¯ìß ý›©ýÁ£üGˆ2¥&Rß?¿œþ!fŒEàÜPXêH¨àx<<D *©W¡ ë†ôþTÇ`e,ŽHÝP› ¸ãð _ª¦€8 þ+üGD"ñ¸¿êLô;ÀÔ-ª»?YƒÊæuûù¿HSÛþEÔÿ-¤EÍtý‹ ªŒÛ„`äTÀP£àq|åR+£ ÆüPªöR…pzü¤  Uˆx©"@ª®ïoü÷04Äù_U:®(©¨C©Ð4Ô5ƒÿW‚„Ç#±Äß?uªþdwu‘H$4ü‡Ð‰º’^C1.è-f”§5ô¨I:_ÙÜ×È9”L‹.ê<ã#?ñÄn§$ë(Ç㜘߮ázCÐ…n“¯á>I{s¾.sYuBvkYç>zKlE~>ü¬ºcIÖâÝD9Õ¾°=g¥ãsž¥ì)ëy¦1qšGß§-w¢ŽkØ™d¡m®E?‘V‡qføcÕ®ûq¦Þbï‰ ¹r¹Vat×@âÚ)`¾—²wicñ¾#ŸY„ï÷Wb"6]%8hä¤-aJìWjŽ9KJ?(bǰ¸BÀî®H°ËÃÒÀ4Ê æÇsý2E?'ò÷VjKÚ‚0ÕŠñúÄn´¦µÀk÷…OÛ¿Ó%Ñ$}nÜ*2vç ÕuÁÈxú•…o‘,$VtDL‰šX¶$[³âÖú´U›Y"/O†k7±¹ZMD×–ß¼Ž[ŸúT¥·³MBüb.âŽyëW¦Oã+.È /—¢…ž8i×§ê„'T ·º( êhÞ™c|1f_ÊQiþbLáûGÛíåÉS>³IjSDå0óInCy‚ßÊN!¯N:·Àz»”T#k¾‚%{|´—ÈgƒúŒ¶ÉMj)Ln{*¸­fœdcj8ox/ &»%R\W¯Ð¶rx íi„Ø—±x$A’…üÜýdÿó† ˜s>ߊú¬mñ’”ò c²öe4Çuô6㞎ÔÝTçÙ ÷eT•¿h:’XçGÊ¡¥g2†’©ã‚ëäüÃB3ô37%'Füi O¦%aç’y®)FŒóé "·”ƒxÈl¥iá õRŒç2çÇ Ìæ,3¶S3ÏoÝ+[x»ªœW¿Ý cwˆ[8â í':’ÝÎO€R ÔIÌS³}©­ZMGnc ¾Q¦ÒVÁ»NN%9jému¾b½(uU$Û ÷æ€+­oÈÙ·×OsM“9V›ê½Áaî0ù7ý¬¦Œ…x‡¶ëñÁÞØ(ŒÄБÇÛ/7Ñ~ “~Õ4ßœUeÍ–æpå_8ã!œ'—çËqhãMÄ#9‡%®O5šq±¯«9¢ÄéW¥ªOÌ›8„®ýìX¨m…e-IÎNDÆ2+?×e.û»oÕgÇfì¨hâX!hÏi7Æ&VŽG[¦šäôy²ötQðyao;éΖ5ÎÐw¥¢¾,ݯt¬»œ~úU´<àÂ1Ϫ¶2O B‡‚±ˆ¹& ¿uÃí$‚HŽa­øÏÇ‚›©l§ÏæÈ±ÛŠ÷m9{öc‚s‰ÝüÞDé3é™ð» V&åY/ÑסQÒa‘ÆEÑJ}~ Ýk3»9´RÀ½^x…ðì×vúv)Æ40Cª Ü®AŠ!0ÿA‹ŸÖñ”k·œ½ÓUÀ·¼³ëL•Št]nh ëP&²iòš3+fY»6€P:ñ8Ç‚¯¼â¼×(éM™¯2zʬ`Î6Yξv6ùŸ"d6“¹:_~¾ùUD©qW°Žìç+Eªç𹞮ô!äÕKo¯î¶×ð~2‘pûØýô«DÙà‚ y¢6OÔç1Í8Ù“7ˆÍ^'V X·ÝC¸Û ÖX=ŒYD醢[^¾`S²ÂÚÅ?·j±®Ò02ÛGP‹Ù”uðyèˆm»/éY$lÚ>íFþT<©Í…f‰˜ÙÛÃ)7~~—çqFJØlØ ¤hì÷¤°ùKÞ–dÚãLÛböú‹eC}œÈ ¯ÞXËCrè)Þ6Õbht&~så,% ¹~MÏÈ/Eœ‘3•C~Εíü˜y©Ï;íék¥Vzü~ Ž1º:Äg.ð‡]”å$̨@ø.—Ÿ:3Mž_Ü‘ÝêDt‰{¤ÀaTc[ Û¯.ÒÏ™ºi-eÙþÕ!’éîÆ7tpç¸å|—àÉOÖ&ébM‘è`Öu3¶3å\Î`Ú!o,OtïŽ,ýRïdtnGͳªšà55ò³q) -‚á%®Ý†ÂܛϽ«–½·äÖévGxˆ±¶·_¿oÀ‡ýü¢'­ê÷åmì cô˜Y5éŽ|H»ƒžÝ™y!(çEBú ½8í÷¼¼›Ž(3æ+¥°$F˜U¹Îmzùå1»}-ÁmµHâêš“ÚåÓ‰"”,¯Àue‰{$wgr§€.7taxÐõhÖMÕíšR=˜Hb â!¬¸8FKµÌ=C¤Ð:rŽåe<û˜.]ZÑnvÝ~,, 0jóÄÌ›WEªê[¾\]³²ïbÄ1È‘;{ã«29­$O™8[¦óåçù 0†]_~éwY§?ûñVcôˆúüa©M¯þÔ·DQ¯ÚK¼—8uMz=kÖËÞZÕ3éN ÊÍ~`ôÂ(>hK[u#-ó§Ge¨“úÅÚ¤õl]:߃w âx‚“K}psÖw¸x¸tž9Tó»Ì[™/“û*ýmïÎKÍq+u+ ]=]°TÙX.è(·cVUtG˜¨ÉQïXfÂ(ü{¯&™¿Ôl\šÜyw7ÇŽ±î.”+;cÄ()/ã¨Ýÿ x$joʆ•œéžóšƒX$_åÄä6Т7%Ç£KK@%“|ÝïïxöšŸ’ #ÖNe9ôeWõnÓ(½]cªE†ß®l£yœ“o¬!)gŸð€ÇûÈÕ-;õ«‹´42ƒûž2ñnâv/ްÂ÷Š”“i»nR8y¯ç¼Zh.{ ãü…·‚U÷¬üœŠô€±Æ5ú罉hÁ™#Â9–ƒX„ ¶Þà ‰Múj=KÑ«µIòkvM' žæÏ[’0¡`ÍFÞ…¢÷ ÃÙtÚ~ÛÓ±a uÖŠ1‚ï½Ô;O<¥7¾§ƒ#¼Ör=?íjÛb›„Ô«_ŒÒrifS´?ãi h—dغq%ÞdVÄ772îØ÷ëÙ3Û®Z•·“ؾ]Z‘°ïCðob9ûWÊ›6ˆf½u°pœAó›þ*­bú¯\RÚ/º·Ô3ч¤}è/•f~Ï·©¼°píR÷ UµÏûdëµ›gD¿Õ÷±0ƒ^ÞY°L@ÑXÿ¼]eÐj”RßL›’œÔA{RêÛ3×ÕíDvUˆ·;_Ä0÷•Çí»!‹^¢Ž'ß1q£dÈ«<”u´ü ½I.Iu¥¸±XÌ…êcݳ~j©èP Y3•uýÆ ?±-F±ˆ[þ1“nᲘÿ'À{s¿«ì5¡€Óæ ïp”’VÜ„„½ÌV£°Àñ'\­G+çºüä xJ®ô”0Ò½›K¢‰¥ø„R]s¾^òk¹…ÝçX{ôÉ},:£Ý.²^DnëAau Î|>ˆß3vfæã-qûËKÓóKc—n •1Y:ï Ýó7¿yAÿœ(ÚI<^X>97æŠñ¾m¬8Ä1 jîֲɿÀTá%Ÿ–U9øVðPª+ð.-éšÌ…ÈâöÏ1>ê „~îéÄ'JJË£F_)·vqÀ)ö·eŽËn‡ŽÔ‘øoYÏ?5*ø¿@«tG½ôwVöNgf>ºÅÆçÉŠ‰òê^pƒ½ü1 (~îƒSM¨5Ô‰ñ£/Pù]7ò*›Í»ð¦~íšÊaø E!¦äæOë-%¸@å›s ìq^.HñŽÂ¯Ì–fV˜©BŸžx«áÃ#A¬Ûy­™åþg÷T²3$kdøé^á¤8¸ßæ•él –È~XS2vC°‰¾>Åñ¬²2^òݱÜÞ¨Ær.ž.m˜hÛ‹ÏEUX:QÄëžËn?>–\rtwÛ%ÖH[F {Õ{²ŒùPÂCÂëËö§ô8Šíý00XéàÐkµ˜>IÁÞ.ÑAûdŒ¾É¹«ío¬óF?DJ§¿ŽæŽ‹8tLëF KZ¾âô~}1B>¦±k :õé˜&Næ¾¶ »DN£± ÿò¸ü-)Õæ”–i+¹}ÙÕ%޳ù 8›³¡^2lá1zM½cSJ&Õ÷ûtŽŽQ`áÅÙoh·ßo6=É12þzƒ}@ÜEò ¼ÿò僞1ŠAE^ˆ[‰5]ŸÔ”äÿø€þ[à?¢„ã‰8 ïúŠˆ‰Xendstream endobj 189 0 obj << /Type /Font /Subtype /Type1 /Encoding 504 0 R /FirstChar 44 /LastChar 118 /Widths 505 0 R /BaseFont /CSREGH+CMSS12 /FontDescriptor 187 0 R >> endobj 187 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /CSREGH+CMSS12 /ItalicAngle 0 /StemV 76 /XHeight 444 /FontBBox [-62 -251 978 758] /Flags 4 /CharSet (/comma/zero/two/six/J/N/W/a/b/d/e/g/i/j/l/m/n/o/r/s/t/u/v) /FontFile 188 0 R >> endobj 505 0 obj [272 0 0 0 490 0 490 0 0 0 490 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 459 0 0 0 686 0 0 0 0 0 0 0 0 919 0 0 0 0 0 0 0 0 0 469 502 0 502 435 0 490 0 230 258 0 230 774 502 490 0 0 333 375 354 502 448 ] endobj 504 0 obj << /Type /Encoding /Differences [ 0 /.notdef 44/comma 45/.notdef 48/zero 49/.notdef 50/two 51/.notdef 54/six 55/.notdef 74/J 75/.notdef 78/N 79/.notdef 87/W 88/.notdef 97/a/b 99/.notdef 100/d/e 102/.notdef 103/g 104/.notdef 105/i/j 107/.notdef 108/l/m/n/o 112/.notdef 114/r/s/t/u/v 119/.notdef] >> endobj 185 0 obj << /Length1 1608 /Length2 9081 /Length3 532 /Length 9996 /Filter /FlateDecode >> stream xÚí˜U\›ëö ¡)V¬x!(VÜÝ))NI¡ 8 ¬¸w‡âÅ‹»w/¸Ûdïó?›Î9—3Wó›ä&ÏúÖ»ÖóÊ÷^„–JYYÜj–B`Ìì,ìIE55‰ìlv6tZZI[0f…H``;??;@ÜÞÀÎ#ÀÅ)ÀƃN „Z;Ûš™˜Âô’ %ñÄ­À¶f† @3[Ák‚,jPC30Ì™ ni Pýk„@l¶u± ³³ŒÌ a°‰õ/'9ˆ1Àû¯°‘½õ¿9€míàRz¸$®h…X:ŒÀÆè¬JPx/0Üäÿ†Ô—±·´TYýUþÖé¿2@Vf–Îÿ“µ²¶‡mŠP#°-ä?SµÀÿÒ“€ZþW#9ÈÒÌPbb °ý+df'cæ6R6ƒšŒA–và¿ã`ˆÑ*ÀîoVùwïÞªÊ2ý³§?V™A`êÎÖÿþ+ÿofdø Ùš9>²±°±±ÃáßÿÒývÒC¨‘~(¸y [[3:ütÀ‰àÂ0ƒ`'¸3+  ƒÀÅ ` µEÿkKá»Îjüwì_È GË‹Àjêlm †<†x¬Öð„=†ø¬ŸÁ¶ÐÇ?€ ÿÃÜlV˜ããsnxS˜©-ø x_¨½ícà/3‡?2¸¬vð5ù‡ájv`‡?Ìàógýמþá°BÌþ›B-¡ƒxàeÄ ^Bâ‘àÃ% >Vê‘àS”þ‡xá”y$¸»Ü#Ák*<¼¦â#Ák*=¼æûˆ^Sù‘à ¤úHðj_õG‚ÏHã‘àÝ5 ÞïÃ#ÁûiÿCð7”ôHðLƒG‚g>6¸šÑßNðø×^þpW“?.kúÂmÍþ@¸„Å·°üáV¥X! \úÂ5¬ÿ@¸†Í×°ýÿ:M |Õ` ÜÊþ„[9üp+ÇG„_άN ÜÊùoüïkBBêäÂÌË`怿"ðéñÃO›Ûÿ–hhok †Àþ¾ƒá—Í¿ÙØ ~5ÁN`Cô™I¨¡ ¯y|õ—|w鬑d;òÄ\ßf¿ÊDA–½EA¼qÛšau0Å1®®¹Y!Nܾ|«‘1÷2Iµ¸k·‹«ß4n7CF’êážÎ§'=i]mÏ­R·f(×­k˜f©Ï–š‘KvØy3IöƒžæOMÞ¸[x .Ï`$QoÄ¡ë¦5(Ä‚5·—"ú¯½…fAg²{ˆt’ÎðïgHÚÆ,æ±ùƒÓ‘&…oŸ±Ï›æã¹è*a`·Ð¸¬íHkV¦*•@òÓb*1§Ó“RÇá+‡Ûgݱ~­Å2#´9®Ù©ý‹Œ%þ´ù¾Üœá~]D«B¬^g>‘9Þøù¿Áø—USZåÜÅþ~‡Ì qLj,§®ß^ÐBrR=+2~²é×Ò¢ÅаŸª¡Òõ7ôêbvÉÄ›ho°”¦‚kp1s3 ÕŸž§4½FbnŠÈ‰S$¶nCByVg;ûâ ÷Ú$#Ó"¹×†1 xI-9j1 Îˆ=‚‘ƒA‚3šw} F¹Œî“a͇0Úöäg>Û*.]' ,£i!î"RרFI¸Ð3¥šçuyã|¾€Õd*ö3—Óàô ©c>OÁñ1èíí¡Óþ‘¥=EŸÖÇïTi9ä/u7q„’k±T€¨¢äÛ¤˜FptŠñýfÏÚIÔ+õF­¿}>t. ¦÷‰¡/¢2=V¯Öùe>7WE3nÀûNÖau|GÊÖ]M»ÏñãÆEEIJ¾ í¤™è\r¬á¶<Æ#ß?€¡š¹49æËÚõé{¾+R1u4YÊ"Á`}>ÒNÖMØuÛêy@›ÔžQ¾S<¶Ûnõ?°>#åççCÕXñ–x¦c«Y™ó ìõÁ7{ÿy7}? ž¯mž%W|Ûˆ¨lÄN±ŸÔ‘÷`íÁ²¹yR¼‘èàn”¯#1Xê ·Ç» %û„^Gë²Âû‹ R\_¶† F„V–¾üWITt££±ÜùÄ”ú9 ÒqëOk“/±ãŠù0çR˜@„|aÈvz!e¯Ù'=:“ŒöÐò;õ÷8‚{´^çl{~'1ï=>«ÅB¤ö~±$o{ãêU12ý^EÈ›ÆCÍbµqm?ÂoþÜïJº¿ìÆ.-Çîž*JYºé|¡xIV*tyBŒ5KJt ›ú}M1šÂ^£ý%GÍ›¥j‰Í³ ˆÚiú‘8¤`¹Þ7ŸZÞ–jk{hp ”ÊqüÇV˜Dôͺ×þÛY\.ÉÍŽ4;ýÅ ”1ƒÀènÙ¢c¯^‰L+ ú6DÑÝ Þ”§ºç«ŒTjSb´r[+ó~^¹£YSnŸˆ‘x·Í©lF%¨¤Nâ,.±¸\bÙ…«æ¢O®€0šì¡­³>=}œ$ h9!môd2d°È©9ýfrâ„ÌþIñžä¤|nµ¾—§ ݼY\ȶtmBs:ßò^û“®ù †eeì¢cVaHŠðöÆ$¢õ{²oÚ×;‹ˆ’ûO¬:ôïÎÚ>´¥å€7NaÉÆs™7«Ûk·X‘²‹M¡ÝsŸ½âÑN 5¬.EŠ._X-” ‘ÚÃØpYø#ë…~wáÄíV‡&sì†&ã 'œô«­²ª'ïÐõR†ê^A/f’¶x7uÉÓÉRÙ ò:8Z¥“w®M©¾=Œ·èG»÷ål$qwRsÒ³ºMÈp˜î•ÕÛOc­Sn͉•±6ó¿¤dv~Ì+žðÛ&j5âFùÞ(hõ¨e£¸íõ¸3‡P1Þ-Š2è,¡¼+ßømdrN›^ï˜?a*+­ëRð²¹s”„a  ÙîGHú˽Žl×$>Š¡ÚÚ±1ÌSì¨ÍzW€ÐT=«,›\Sé “ë^Â"ÙYAÞÔ‘ ã7B (Öˆr^EjW”®ýé.4‹'‚iKa}"™nyýÐåÕSòìX¼c^€çõÙ¼ f°ì· P$vÆÈ(ÁFÕ+­Çžëâýê•lÄG)Ê}\U“\í­’ì¯_º øª‘ådžñ7h 4³™_ˆa{A†Óáû;»SëRúÖ•nˆ…E´…$ÎÃM‚ZÕ\™í=úÁ¿‡P|£¤…$fÅ,+’AëDȦ%UÅᾨSVŬ켪—‘*hÚ[]éwjEŠ‚ Ž®¨mÏsÉ{ÝV8Sñ¬œ“C{\dó…2b¶=R”ñt€Ðª¬íõ@,²Ÿ&•èÄ=T|½lk ¿“e/¯±fn1w–<‘pjƒûÆñïñEù(K>/·gUÆx`|µkº.¯Æßдšù*"õ“vÇÑôgCã[Å~¸0R‰B¯«x•_¡äÄ;ïêE+iw‘\,ºÚ#eŒÚÝï ?Ë0#$ä×ù~1½&Ú/%E` oÛ?ä zˆ"ò1»ä…¾q¦¼ÐÖiTž:K;\©ü,ödKÿÞÍÇãÓ0õ¯SéN\±YnB‘³²—AM︒9Iuœ” Þ…·rZŠ*)n˜9yZ­l=;ôfÈsuÌã-Qý[ý—¨ ›ä¯Ò7!/<Åm)AÓo5ET¦:†<˜¬ Á‡bÂÒaiÕý˜HVß~ÀÖ[’ëøòœ½M$%Ø[Éôo¤åËÛOM©Ë¹eò{{‚f öF ¶ùY­ó¯Ä’9XÃÔ]vA=S~'c’·C“ã÷xaéíX[í&/·™À®§r;õZÛÕ^Ëô;›jáE—°üöì'êq!I6Ðòæ¶l¡×É,íHèÐêW­GÖwoåPKY›osu&4ìŽE ¯¿§^V˜Ð|ÃËzø¶mšÅ(õ4¼ÞT&ä‹@»,ZXíæ0w,MôËÅVLºæÆìÍó"’Šéœ@È>!Ux'¯e9êD [-Ž>G2Kè|¯é¢3Æ¯Š¬øÕf0|gÞ÷bOB븭žÙmâpv\Ûv}3Òæ^«81ø)Œˆ·óä=¥\‹ŽcƒO%Ì-(C)ßÉ»ƒl]De6wèÖ*¢åØøÐc» ¢¯ã˜e×ö¶vÉ)ç4Š|ó@Є‚ÏÌÚ—B]›á¤(í[·Ý.§_Ð08‹[ Óh…4†û « e-Ï¥gF¹æè;©7_^ÛY¿ŒqD¶Q¸b¢se•…ÏÏÍy¿‘°%¿ü´—o$æñ`©BߊËSxvýô‡ÁSâÝõòÆ/¡1Ò·G6Âo|õõQÌG¥ J½j ^Mƒ¯LzxÎ{•‡Ôã¶ž«Î &Ñ1xƒøs„ êÊç¨eõvi«(ì—ûB‚P®Þ²@yuj+)Ô ÑgOñÇ%H8e7|rÙõä“Ì©=6êMè(HHÜ¥ð_©äÜm~AP—Þ<»¬!œáÊ@B|‡,Êú%3žíÓ¼¹VÈ”IkzbAÈÔ›q«¸ÎA”ý—<^*K»€'iÁÅZW†êÈ*ƒ˜Œ}Е]yûã©=ü,ñ%_{ æ'´+$Ùºj»í†‘pym7¬b^…YKRTRü}çS ³ÁíÑ^rñ+–™Âi&¦Í¼œê|HCâü¢Õ8fËùùJUÁ*Ew*>¦ò8?ŠŒÉ²Ì ‚ð'¾²޵¤R·„#fâÛÁÞC{Aãþ HO»ªîëòz.uRµžøVávs¬×Äc˜7ã< s>GÆ)»1W Xó1ÄÏ:÷çO8Áb޽—ô¤r˜rð¶i]ýaÝžJ¨I{±Ixlì¾øš€&âéÓüÅ4îNN’š!®WÀ#ñ3ÿƒh,{üêùÑúýoÖÐ NÏÝc‚F™qØtaS'®±¡~â¹sKIMä {Ÿ5×áçžÙ‚âåp›ozêk{—´òV®tåa=Býö ½½õ&¤.¯M~1o©ºž;…56+$Ng¾xZšjF¥£o™ºsžõ‰">àØn©‚ºìsl¬uŒ30î¹îK4ªZœfú”•dM–×R"~¶\oŠt&•„aUfÈÈ›ˆ§Y kªfмº©èý@©º\Ùçóõ´Í@†ƒö—Ê~²ìñ§ïÀÞPÉQ3K|É¥…°}ì:h/qžløáŠ© }ŽxéhÔðñem¯uµw¶œBˆt þŒéטì×®Á5žãÜZ7îñänLì ~Öÿ‘ `Û$´N­ËÜ9Ñ@]*ÀÐ)\EÖÑòR»±ÕfµDŸnT2q_»5vˆEa*Sx†11y@9‰ TH?ѼíÄ•ÿyøIóûIP%ñîbH¾æ`1KÖûžâEK„øM‰úwýûç3Ê‚:CÏŠ´Ü'ܯG:¦.†3óÍ™Ïü‘¸w¿ ×ÿÐÕU–å¶KÁ/ëF'Æc#(£ÇA*‚Ö߀hýF4OD.Þ¾‘UEq˜2úmüRWy)³‡õÚ†§µár5éã½¹ÒÑ«·7Öb8myz¢4Ë9êßL«“4$ø(²v鞃|û8€!jé?ªŸ Ÿb!s^[?œsU øR3ËÂñÒx e‚/9d§$U§ì~Ù,ëšÊ0Çèõ¶ÖXáÌuÃDž§áÖy@º0†¾r8ðÊ1ªØ§VQÖPe£–Ri©1Õ‰åáÿÃ`Y)#ó&j7ö Ž{ÈòÄ9ª ¡‘Nw^^w2i^¯§”HÒÓ1]¬’°3)[‡æ³$KmQ@¾ú­‡Ø»S4*6jñY ìk†“. "/ÅgúÆ|à6ÙmÞ›)ålÆ8öÕ…ëë"™“•­šÛ“ 1óŠ[[É·D}°Ï_†GÌ2÷žy¥î„àTÝϤÄ:¬VGÝÐU.k1šû|5H•ùÝäl…¦Îõah…¯6Qcˆ qjŸ–»‚û6Œë]÷žóÑ®ïCjšÞë–?è8¥Pq)_“pF„ÌaÜ«?) e¢LSšú®5›[`ŽŸÌA,ÄCú±†ùìÒüÅ1)·9¡ÒĺÏ=Šý¹åg”™Ç6÷C¬`é3(ÆÔýyñ÷°Æ‘[ Ë [+¿Ù!Áù7Ý3ÕnúóŸQÐïk^ºqXKQmy€§NʈxcwŸ¯C†~Íw½À/ÇB“I´£ìåå u;úDt¨meÙ)û° RóÀˆW;,0ŒÃ°~™9E²·__ú¥HŸ°[×HI  Señ,dôoëjŸ|jš4&£)jï"WCj Ê÷¤óÛ>¬ñZ-ù¨ï-y(¥{w<ùiîºúèå¼ð ·@¿8PÉ6Óp>hP¹6œqíg ©xŸ'ïd¥–SC¯°CpáJ€Gó˜†IÒO’A‘^žú>f»Å¯eÁýÙO0Ù+E^‡nkgX‡ò«ǯuXÔÛ„ ]€ÈÇqjœÕ…m ¸"úÕ÷Å,˜*~~’[Öv 9 ÖržŽ7˜æØoÒ+xÇ$Î6‘zlAá¤H³j@F}k‘3®Y%AÔ·K'ô '¸Oêï?Â2ØÆ_«°z›ÚQrÖü„–¦Ü=´x%)Rã¡8’¯?ÒÕ& gÏ··–d”‹˜K4¶¡Íç†â‹""¡{°¢¶Åù½:b¿ídî#Û§nõÏ/­ñR‰¼žúláj 8_hL'.|·Š;ŠÜNœmµªg8ß'ÃîAéz1]'ÆÖŠoTҠ㪲:Ù@a^qˆtàýÑéggôºÛB\‹â¯ù.IùÛ‰g™ÕƒªZÊjW¬€‰Ä2<ÛÓêŠÍÐô×@·‘oƒßÇçå/§6޳ؕ¤VDx·»¥..ïéErÅ)`vŸüv+6ÆÐø¶=Ϙ ˜Òß$#9Mua§ü/'ÁË=™Ø(§Â“ÉWl]´¶KdJüªæí¯u½¯m6BSïOœ›σô™~·ï&7¾ÕÒK¼,fw> ”BÖìLµÆJM§ºXž{(Û™ :ýbà'(?_;{cLè÷ëÆOíκKF¥@þùƒËO(¼æÙêH"3óöÂ…ç»ËâèˆdRHÃÝ „³èãçÞ±7Ÿ¤ûäÊjÊ‚r%Ê]žIMicß‹hêbÛ ÌbI3Ê“d– T*9tÒ]æ\+þÁQ¾¡öD·°ý˜gƒ¼Qõ¢äÇöp}øÆx‰>GëI´¬ó½Y²ØÆTpeÖO(†?ò$®ùí™¶ Ú¯ö\ «¢V,ã&胪š:æPßµäÄ{îZ®FdVd¿ûõNþ§å¾_×Öa¡çÚ·m°Ó`he÷Î$fýÌxíÍ­â| œ0ô¹-RHAÀäŒÆ9o*DK³ÅÄ—@C™I*;âÞ/®ˆïEì°Ã+ãys`ä‚cÄ)¼ð‹¶yë²ÕzvšõÉj¶B\úµíC{3†¾æÃïäOËØw:ù"v!”Þô…eг­ñ%öƒCØ +I?J¦²v‚– ¹ää"q~—¹Cïàý¯}Ú+  Z1Z—Öo³-B’T4p.8ªkW½ϩӉ/:|šĿM»w¶î'ÃrYCÀÈ·ehÈY‚.ÄS¹b㔲t;?îníÁò´°Ú„&D‹`»BËCË3†éffω¤y~õØ9²¡ôÙe>ýKd¤°…iç´±#ˆs•_wÆ[…uÉ9Øú ôóæ±Î¥/˜(„UÏh,RSmxQ/êGû‹JCV’‡«pªò؇åÍV8ët&ñg0)_è¹r:1«h„ø³Ö®0ÍOäSy?ù4ß4j“Å–î ö×áç Õî5ù Ûh²·ŠÊ·»þ°`E_ñ§8çâ@ÁVdL}¦,ò>|òÌFºWQ?:C´QšO)f?y±ö1n%h—aO1ØÐ¬%[!tx·×æf%< £&Wúô4¡T0Üþ ±Â>ÿxÙm›Ó@ bè$ë'ú]Xmç^ag£3±á@ÍÔ‚è-¹£ì8ýª0 ÊR‰ËË~J9&yãO&/n¶2U9ìâÇ€þ鬭_ 6bF^|êÜ'‹¤TüUy5ÐöiṊ*&Z‹±+û|P)NT-*d×7¯|÷Ö?¥,¹[ÝgØkŒcƒþ®,ö”…ç–Rtéab¥ˆ}‰zŸ ÖQ£cv€² 4>ë^nCÞ”xÑ’ [jÍ£’¼U/Ȱ¥žÚŽPMá ò=ÑÑâY–CícPå 9 6á´Šéܫ쒷¹4yK®á´¡9Á˜ AZoCnŽB úPß—EDØP¶‡Hê+ÆûºRÙ–ÕS9Ö¸¤42iµÏüìŽRýpº2Ti¸ÏmëÔg#xÖ2T×ñݱ¤„V†'l°Þüîš»~$ó<­’¯¼úÏ/'Ÿl8ÆóÒ0˜ê¾0¼ç,”0Ê(Uï6«ø´$µKê^ÿöNÅy¯ëB^È¾Ê †)­CnÓKéwlƒ„*ª°$,¤gýƒ¸]ÖmÖ’`Ÿ½Iع þ 9´»£úÃD/%NBéö±‘˜‚ûþ‚Ê)Â÷6"lï jH¾aíÜíæ²˜ì{mÌx—fyØTÖ°«­§,}üU{–IÕDœ”íêÛ=_v%]8³(§¿¶ôŲqf•RmìU‹ü»F©»{Êë׈óX¢RFÇ•f… Ñ%í“…w®ˆ”­%[$JNo[îej룽p7µ0‘…ªåõ~â¢Iãƒìý¡…bÀÛúéðdRòƒ—›zy”YÓÄë-á?Ñ­Q+’d'I˜ˆó¥©+šÂzBŸb¼ì\£SJ²Ê§hÛbçvòÑÒf.WͨŸ¤Ö>_祛Œì)ð^O¡a$€ïp,ëyuT*¢ISNëTÙ¡.Î…éR /‘ýM_”µ­K®7x•¨YTotO‰”ïW¡}»2ŒŒAð™ —?™ªvcèmbqHáWÓß4׊©¸:UkDŽ V9Ku6óξZk¥*¨7‘÷í·…ÓôRdØA²ï§-ÊuìHE¿GÊæuíá›U¶Ed±}óaàØã®°ÏÚTFá&±}rg,'h!Hnce}ÿõõ5½¹ª§sýqùGÙ‘‚颣b¨ªGâU[îãNò’†éïi§í½Yüú_’´A…˜e• Ë|äm×VÏ­²gÚ±RôL¦Éo·=\Û¼nÔ¹¼aê“"-]q;0m‘‚®+v¦‡ôÁÅ]ê•2“ºêÖ">™‚c2™§À¤e@ÐËXÏðÈÅgº¶W\OS®Ï¿M£ô7|fÛŒ’3û¾I"$æ×êïKk|L‡Q50aû=Ýw‚HµŸ1ssoæïÓ}iwÕH6ߪ§û +%e +îYôþæêȳw!¥6èæ™èÛ¬Y¶` ¡‰><Ý¢!>Yåûên2~ ì/‡ÎB•ZV&¯R™Ò5ËcpuôêÕÛžw%qfÔ©åšÒ‹cu û†îè®sgÌ%vÞ7Òäû%\Œ[g)GAå%*m‹~–M&8Ôò5÷9¿B{¡Üô¥^sèÎ!u€¼µl0ëc¶!—ê÷d"ÈAÕy;É06“ñ­¡•J­þå]^={s3LÙxƒg—dÌ“×2ÏgÑq£ÅvYλÝH—Ã9¹Wmó;lû­ËÅ®5®|¬?Mÿ4p€ååë–‘‡ëƒup—ËëŒÀßj!ZÛg6Ú ÕØÅÂwKÝá oרhäÙ½ÅQ ·à€¸åºó^(]å±A¾ 4Wš¶?»QÿA4ýúSËáu‚ ðhAþ„ö 8b’F~Ìd?ƒh4y‚õ$æÆ÷‰»+3oÿ-óiKzjïzÈ÷41æË0¢£ögR³ñQdâÉAÀ¦øSfÝ&#Z—†5_@ËmåUC}rM[ÀþלQ#gêg–<ÜM¢zôQ§N±&Ïi,ü?‘ ¯Ûã(YôìÝ{…•åtßdŒ*Þ \¬ÕêæÂ-1Ò;LßïW ©`RÙN4ˆ²¡ŸöA½¢¶³×ÅŒN“K´¬¡1(ŽèE4ÏñÄ*‘Tú%Ãà£Í@³â}ùý¿y >]¼â-\3cªF7.ô<úE>!áÍ´æÃ‰h‘ß$?úpi]Œö;ˆê²k‚.ÊcCR°£rËøTyZ„Ü_à‹çå2"H7‹w åK𕆹Ym}NFñO¥®Ë\jfQ‡D¢ µÆÜôÀ—ø´ Ö'SÝy RQ ³Šq.WCÁ‹Èf—µ³?RJ^ÐÛó¾ `4"¯3 k0çg{sÂÌ“|[½—A1i'ûd‡¸Š{éø "½ÈÌ.´ˆ¸7YO«õ¬>ÚNÐëŒ7–äPïFÅ™=ZX$(ª‹z­±í°pø m•sŒœé¨Lú½ "ï(+4‡<ñš!Aé»LféËñmËð…LÒ>ùéC Àh¬íwZNñÌrg{"v¿ 4”Á+%kŒâ­ùkï®gÔ'‹[ ¶K>TíD~[3h¾oÏrÁšÃÜWüˆ«U÷_IMBæ•%é”^訅/ îÕíõ¿ >µ1’B”6äSEcdždú-àªèü‚Êé¾%N¦ø6_cÁTóg ¯8çVÙm;Æ^‹§ëtµæ¿/X Ïп(±ý~Ðÿÿ' Z‚A¶0¨ÈÖý¬¡:Ïendstream endobj 186 0 obj << /Type /Font /Subtype /Type1 /Encoding 506 0 R /FirstChar 11 /LastChar 121 /Widths 507 0 R /BaseFont /KJJGRH+CMSSBX10 /FontDescriptor 184 0 R >> endobj 184 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /KJJGRH+CMSSBX10 /ItalicAngle 0 /StemV 136 /XHeight 458 /FontBBox [-71 -250 1099 780] /Flags 4 /CharSet (/ff/fl/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/A/B/C/D/E/F/I/L/M/N/O/P/R/S/T/U/V/X/Y/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y) /FontFile 185 0 R >> endobj 507 0 obj [642 0 586 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 367 306 0 550 550 550 550 550 550 550 550 550 550 306 0 0 0 0 0 0 733 733 703 794 642 611 0 0 331 0 0 581 978 794 794 703 0 703 611 733 764 733 0 733 733 0 0 0 0 0 0 0 525 561 489 561 511 336 550 561 256 0 531 256 867 561 550 561 561 372 422 404 561 500 744 500 500 ] endobj 506 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff 12/.notdef 13/fl 14/.notdef 45/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 65/A/B/C/D/E/F 71/.notdef 73/I 74/.notdef 76/L/M/N/O/P 81/.notdef 82/R/S/T/U/V 87/.notdef 88/X/Y 90/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y 122/.notdef] >> endobj 215 0 obj << /Type /Pages /Count 6 /Parent 508 0 R /Kids [178 0 R 223 0 R 277 0 R 297 0 R 311 0 R 337 0 R] >> endobj 367 0 obj << /Type /Pages /Count 6 /Parent 508 0 R /Kids [359 0 R 369 0 R 374 0 R 380 0 R 389 0 R 401 0 R] >> endobj 424 0 obj << /Type /Pages /Count 4 /Parent 508 0 R /Kids [412 0 R 426 0 R 446 0 R 463 0 R] >> endobj 508 0 obj << /Type /Pages /Count 16 /Kids [215 0 R 367 0 R 424 0 R] >> endobj 509 0 obj << /Type /Outlines /First 7 0 R /Last 147 0 R /Count 4 >> endobj 175 0 obj << /Title 176 0 R /A 173 0 R /Parent 147 0 R /Prev 171 0 R >> endobj 171 0 obj << /Title 172 0 R /A 169 0 R /Parent 147 0 R /Prev 167 0 R /Next 175 0 R >> endobj 167 0 obj << /Title 168 0 R /A 165 0 R /Parent 147 0 R /Prev 163 0 R /Next 171 0 R >> endobj 163 0 obj << /Title 164 0 R /A 161 0 R /Parent 147 0 R /Prev 159 0 R /Next 167 0 R >> endobj 159 0 obj << /Title 160 0 R /A 157 0 R /Parent 147 0 R /Prev 155 0 R /Next 163 0 R >> endobj 155 0 obj << /Title 156 0 R /A 153 0 R /Parent 147 0 R /Prev 151 0 R /Next 159 0 R >> endobj 151 0 obj << /Title 152 0 R /A 149 0 R /Parent 147 0 R /Next 155 0 R >> endobj 147 0 obj << /Title 148 0 R /A 145 0 R /Parent 509 0 R /Prev 123 0 R /First 151 0 R /Last 175 0 R /Count -7 >> endobj 143 0 obj << /Title 144 0 R /A 141 0 R /Parent 123 0 R /Prev 139 0 R >> endobj 139 0 obj << /Title 140 0 R /A 137 0 R /Parent 123 0 R /Prev 135 0 R /Next 143 0 R >> endobj 135 0 obj << /Title 136 0 R /A 133 0 R /Parent 123 0 R /Prev 131 0 R /Next 139 0 R >> endobj 131 0 obj << /Title 132 0 R /A 129 0 R /Parent 123 0 R /Prev 127 0 R /Next 135 0 R >> endobj 127 0 obj << /Title 128 0 R /A 125 0 R /Parent 123 0 R /Next 131 0 R >> endobj 123 0 obj << /Title 124 0 R /A 121 0 R /Parent 509 0 R /Prev 11 0 R /Next 147 0 R /First 127 0 R /Last 143 0 R /Count -5 >> endobj 119 0 obj << /Title 120 0 R /A 117 0 R /Parent 55 0 R /Prev 115 0 R >> endobj 115 0 obj << /Title 116 0 R /A 113 0 R /Parent 55 0 R /Prev 111 0 R /Next 119 0 R >> endobj 111 0 obj << /Title 112 0 R /A 109 0 R /Parent 55 0 R /Prev 107 0 R /Next 115 0 R >> endobj 107 0 obj << /Title 108 0 R /A 105 0 R /Parent 55 0 R /Prev 103 0 R /Next 111 0 R >> endobj 103 0 obj << /Title 104 0 R /A 101 0 R /Parent 55 0 R /Prev 99 0 R /Next 107 0 R >> endobj 99 0 obj << /Title 100 0 R /A 97 0 R /Parent 55 0 R /Prev 95 0 R /Next 103 0 R >> endobj 95 0 obj << /Title 96 0 R /A 93 0 R /Parent 55 0 R /Prev 91 0 R /Next 99 0 R >> endobj 91 0 obj << /Title 92 0 R /A 89 0 R /Parent 55 0 R /Prev 87 0 R /Next 95 0 R >> endobj 87 0 obj << /Title 88 0 R /A 85 0 R /Parent 55 0 R /Prev 83 0 R /Next 91 0 R >> endobj 83 0 obj << /Title 84 0 R /A 81 0 R /Parent 55 0 R /Prev 79 0 R /Next 87 0 R >> endobj 79 0 obj << /Title 80 0 R /A 77 0 R /Parent 55 0 R /Prev 75 0 R /Next 83 0 R >> endobj 75 0 obj << /Title 76 0 R /A 73 0 R /Parent 55 0 R /Prev 71 0 R /Next 79 0 R >> endobj 71 0 obj << /Title 72 0 R /A 69 0 R /Parent 55 0 R /Prev 67 0 R /Next 75 0 R >> endobj 67 0 obj << /Title 68 0 R /A 65 0 R /Parent 55 0 R /Prev 63 0 R /Next 71 0 R >> endobj 63 0 obj << /Title 64 0 R /A 61 0 R /Parent 55 0 R /Prev 59 0 R /Next 67 0 R >> endobj 59 0 obj << /Title 60 0 R /A 57 0 R /Parent 55 0 R /Next 63 0 R >> endobj 55 0 obj << /Title 56 0 R /A 53 0 R /Parent 11 0 R /Prev 23 0 R /First 59 0 R /Last 119 0 R /Count -16 >> endobj 51 0 obj << /Title 52 0 R /A 49 0 R /Parent 23 0 R /Prev 47 0 R >> endobj 47 0 obj << /Title 48 0 R /A 45 0 R /Parent 23 0 R /Prev 43 0 R /Next 51 0 R >> endobj 43 0 obj << /Title 44 0 R /A 41 0 R /Parent 23 0 R /Prev 39 0 R /Next 47 0 R >> endobj 39 0 obj << /Title 40 0 R /A 37 0 R /Parent 23 0 R /Prev 35 0 R /Next 43 0 R >> endobj 35 0 obj << /Title 36 0 R /A 33 0 R /Parent 23 0 R /Prev 31 0 R /Next 39 0 R >> endobj 31 0 obj << /Title 32 0 R /A 29 0 R /Parent 23 0 R /Prev 27 0 R /Next 35 0 R >> endobj 27 0 obj << /Title 28 0 R /A 25 0 R /Parent 23 0 R /Next 31 0 R >> endobj 23 0 obj << /Title 24 0 R /A 21 0 R /Parent 11 0 R /Prev 19 0 R /Next 55 0 R /First 27 0 R /Last 51 0 R /Count -7 >> endobj 19 0 obj << /Title 20 0 R /A 17 0 R /Parent 11 0 R /Prev 15 0 R /Next 23 0 R >> endobj 15 0 obj << /Title 16 0 R /A 13 0 R /Parent 11 0 R /Next 19 0 R >> endobj 11 0 obj << /Title 12 0 R /A 9 0 R /Parent 509 0 R /Prev 7 0 R /Next 123 0 R /First 15 0 R /Last 55 0 R /Count -4 >> endobj 7 0 obj << /Title 8 0 R /A 5 0 R /Parent 509 0 R /Next 11 0 R >> endobj 510 0 obj << /Names [(Doc-Start) 183 0 R (Hfootnote.1) 220 0 R (Hfootnote.2) 221 0 R (Hfootnote.3) 308 0 R (Hfootnote.4) 309 0 R (cite.rfc1035) 410 0 R (cite.rfc4035) 357 0 R (page.1) 182 0 R (page.10) 382 0 R (page.11) 391 0 R (page.12) 403 0 R (page.13) 414 0 R (page.14) 428 0 R (page.15) 448 0 R (page.16) 465 0 R (page.2) 225 0 R (page.3) 279 0 R (page.4) 299 0 R (page.5) 313 0 R (page.6) 339 0 R (page.7) 361 0 R (page.8) 371 0 R (page.9) 376 0 R (section*.1) 226 0 R (section*.10) 384 0 R (section*.11) 385 0 R (section*.12) 386 0 R (section*.13) 387 0 R (section*.14) 392 0 R (section*.15) 393 0 R (section*.16) 394 0 R (section*.17) 395 0 R (section*.18) 396 0 R (section*.19) 398 0 R (section*.2) 353 0 R (section*.20) 404 0 R (section*.21) 405 0 R (section*.22) 406 0 R (section*.23) 407 0 R (section*.24) 408 0 R (section*.25) 421 0 R (section*.26) 422 0 R (section*.27) 423 0 R (section*.28) 458 0 R (section*.29) 459 0 R (section*.3) 355 0 R (section*.30) 460 0 R (section*.31) 461 0 R (section*.32) 466 0 R (section*.33) 468 0 R (section*.4) 362 0 R (section*.5) 363 0 R (section*.6) 372 0 R (section*.7) 377 0 R (section*.8) 378 0 R (section*.9) 383 0 R (section.1) 6 0 R (section.2) 10 0 R (section.3) 122 0 R (section.4) 146 0 R (subsection.2.1) 14 0 R (subsection.2.2) 18 0 R (subsection.2.3) 22 0 R (subsection.2.4) 54 0 R (subsection.3.1) 126 0 R (subsection.3.2) 130 0 R (subsection.3.3) 134 0 R (subsection.3.4) 138 0 R (subsection.3.5) 142 0 R (subsection.4.1) 150 0 R (subsection.4.2) 154 0 R (subsection.4.3) 158 0 R (subsection.4.4) 162 0 R (subsection.4.5) 166 0 R (subsection.4.6) 170 0 R (subsection.4.7) 174 0 R (subsubsection.2.3.1) 26 0 R (subsubsection.2.3.2) 30 0 R (subsubsection.2.3.3) 34 0 R (subsubsection.2.3.4) 38 0 R (subsubsection.2.3.5) 42 0 R (subsubsection.2.3.6) 46 0 R (subsubsection.2.3.7) 50 0 R (subsubsection.2.4.1) 58 0 R (subsubsection.2.4.10) 94 0 R (subsubsection.2.4.11) 98 0 R (subsubsection.2.4.12) 102 0 R (subsubsection.2.4.13) 106 0 R (subsubsection.2.4.14) 110 0 R (subsubsection.2.4.15) 114 0 R (subsubsection.2.4.16) 118 0 R (subsubsection.2.4.2) 62 0 R (subsubsection.2.4.3) 66 0 R (subsubsection.2.4.4) 70 0 R (subsubsection.2.4.5) 74 0 R (subsubsection.2.4.6) 78 0 R (subsubsection.2.4.7) 82 0 R (subsubsection.2.4.8) 86 0 R (subsubsection.2.4.9) 90 0 R] /Limits [(Doc-Start) (subsubsection.2.4.9)] >> endobj 511 0 obj << /Kids [510 0 R] >> endobj 512 0 obj << /Dests 511 0 R >> endobj 513 0 obj << /Type /Catalog /Pages 508 0 R /Outlines 509 0 R /Names 512 0 R /PageMode /UseOutlines /OpenAction 177 0 R >> endobj 514 0 obj << /Author( Jelte Jansen, Wouter C.A. Wijngaards )/Title(Response Differences between NSD and other DNS Servers)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfeTeX-1.21a)/Keywords() /CreationDate (D:20061102103525+01'00') /PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4) >> endobj xref 0 515 0000000001 65535 f 0000000002 00000 f 0000000003 00000 f 0000000004 00000 f 0000000000 00000 f 0000000009 00000 n 0000256611 00000 n 0000416511 00000 n 0000000054 00000 n 0000000084 00000 n 0000262450 00000 n 0000416387 00000 n 0000000129 00000 n 0000000201 00000 n 0000262511 00000 n 0000416313 00000 n 0000000252 00000 n 0000000310 00000 n 0000262574 00000 n 0000416226 00000 n 0000000361 00000 n 0000000421 00000 n 0000267655 00000 n 0000416102 00000 n 0000000472 00000 n 0000000499 00000 n 0000267717 00000 n 0000416028 00000 n 0000000555 00000 n 0000000616 00000 n 0000267842 00000 n 0000415941 00000 n 0000000672 00000 n 0000000733 00000 n 0000270496 00000 n 0000415854 00000 n 0000000789 00000 n 0000000841 00000 n 0000270621 00000 n 0000415767 00000 n 0000000897 00000 n 0000000964 00000 n 0000270748 00000 n 0000415680 00000 n 0000001020 00000 n 0000001109 00000 n 0000272735 00000 n 0000415593 00000 n 0000001165 00000 n 0000001254 00000 n 0000275206 00000 n 0000415519 00000 n 0000001310 00000 n 0000001401 00000 n 0000275333 00000 n 0000415406 00000 n 0000001452 00000 n 0000001496 00000 n 0000278109 00000 n 0000415332 00000 n 0000001552 00000 n 0000001605 00000 n 0000278232 00000 n 0000415245 00000 n 0000001661 00000 n 0000001728 00000 n 0000278356 00000 n 0000415158 00000 n 0000001784 00000 n 0000001842 00000 n 0000278481 00000 n 0000415071 00000 n 0000001898 00000 n 0000001976 00000 n 0000278606 00000 n 0000414984 00000 n 0000002032 00000 n 0000002115 00000 n 0000278731 00000 n 0000414897 00000 n 0000002171 00000 n 0000002253 00000 n 0000281761 00000 n 0000414810 00000 n 0000002309 00000 n 0000002380 00000 n 0000281888 00000 n 0000414723 00000 n 0000002436 00000 n 0000002499 00000 n 0000282015 00000 n 0000414636 00000 n 0000002555 00000 n 0000002637 00000 n 0000282142 00000 n 0000414549 00000 n 0000002694 00000 n 0000002777 00000 n 0000282269 00000 n 0000414460 00000 n 0000002834 00000 n 0000002927 00000 n 0000282396 00000 n 0000414369 00000 n 0000002985 00000 n 0000003062 00000 n 0000285259 00000 n 0000414277 00000 n 0000003120 00000 n 0000003184 00000 n 0000285385 00000 n 0000414185 00000 n 0000003242 00000 n 0000003316 00000 n 0000285511 00000 n 0000414093 00000 n 0000003374 00000 n 0000003439 00000 n 0000285637 00000 n 0000414015 00000 n 0000003497 00000 n 0000003569 00000 n 0000285762 00000 n 0000413884 00000 n 0000003616 00000 n 0000003688 00000 n 0000285825 00000 n 0000413805 00000 n 0000003740 00000 n 0000003797 00000 n 0000289152 00000 n 0000413712 00000 n 0000003849 00000 n 0000003908 00000 n 0000289216 00000 n 0000413619 00000 n 0000003960 00000 n 0000004028 00000 n 0000289343 00000 n 0000413526 00000 n 0000004080 00000 n 0000004142 00000 n 0000289471 00000 n 0000413447 00000 n 0000004194 00000 n 0000004250 00000 n 0000294080 00000 n 0000413329 00000 n 0000004297 00000 n 0000004366 00000 n 0000294141 00000 n 0000413250 00000 n 0000004418 00000 n 0000004475 00000 n 0000294204 00000 n 0000413157 00000 n 0000004527 00000 n 0000004586 00000 n 0000298134 00000 n 0000413064 00000 n 0000004638 00000 n 0000004726 00000 n 0000298262 00000 n 0000412971 00000 n 0000004778 00000 n 0000004864 00000 n 0000298390 00000 n 0000412878 00000 n 0000004916 00000 n 0000004982 00000 n 0000298518 00000 n 0000412785 00000 n 0000005034 00000 n 0000005125 00000 n 0000301731 00000 n 0000412706 00000 n 0000005177 00000 n 0000005254 00000 n 0000006568 00000 n 0000006734 00000 n 0000214275 00000 n 0000005306 00000 n 0000214149 00000 n 0000214213 00000 n 0000411114 00000 n 0000400833 00000 n 0000410950 00000 n 0000400050 00000 n 0000395521 00000 n 0000399888 00000 n 0000213480 00000 n 0000394924 00000 n 0000393140 00000 n 0000394764 00000 n 0000392635 00000 n 0000389865 00000 n 0000392472 00000 n 0000213638 00000 n 0000388769 00000 n 0000381117 00000 n 0000388607 00000 n 0000380521 00000 n 0000378714 00000 n 0000380361 00000 n 0000213796 00000 n 0000377613 00000 n 0000368425 00000 n 0000377453 00000 n 0000213973 00000 n 0000367824 00000 n 0000364875 00000 n 0000367663 00000 n 0000363968 00000 n 0000357764 00000 n 0000363808 00000 n 0000412218 00000 n 0000009672 00000 n 0000009873 00000 n 0000009920 00000 n 0000213458 00000 n 0000302213 00000 n 0000302181 00000 n 0000224800 00000 n 0000217300 00000 n 0000214479 00000 n 0000224674 00000 n 0000224737 00000 n 0000217770 00000 n 0000356807 00000 n 0000348885 00000 n 0000356645 00000 n 0000217926 00000 n 0000218082 00000 n 0000347523 00000 n 0000331940 00000 n 0000347362 00000 n 0000218242 00000 n 0000218403 00000 n 0000218564 00000 n 0000218730 00000 n 0000218895 00000 n 0000219060 00000 n 0000219225 00000 n 0000219391 00000 n 0000219556 00000 n 0000219722 00000 n 0000219888 00000 n 0000220054 00000 n 0000220220 00000 n 0000220381 00000 n 0000220547 00000 n 0000220713 00000 n 0000220879 00000 n 0000221045 00000 n 0000221211 00000 n 0000221376 00000 n 0000221542 00000 n 0000221707 00000 n 0000221873 00000 n 0000222037 00000 n 0000222203 00000 n 0000222369 00000 n 0000222536 00000 n 0000222703 00000 n 0000222870 00000 n 0000223037 00000 n 0000223204 00000 n 0000223371 00000 n 0000223538 00000 n 0000223705 00000 n 0000223872 00000 n 0000224039 00000 n 0000224195 00000 n 0000224354 00000 n 0000224515 00000 n 0000226379 00000 n 0000252357 00000 n 0000226149 00000 n 0000224911 00000 n 0000252293 00000 n 0000250371 00000 n 0000250531 00000 n 0000250692 00000 n 0000250847 00000 n 0000251008 00000 n 0000251169 00000 n 0000251329 00000 n 0000251489 00000 n 0000251650 00000 n 0000251811 00000 n 0000251972 00000 n 0000252132 00000 n 0000229264 00000 n 0000229472 00000 n 0000229519 00000 n 0000250349 00000 n 0000256798 00000 n 0000255447 00000 n 0000252483 00000 n 0000256548 00000 n 0000255621 00000 n 0000255832 00000 n 0000256043 00000 n 0000331622 00000 n 0000329585 00000 n 0000331463 00000 n 0000256201 00000 n 0000256391 00000 n 0000256670 00000 n 0000256734 00000 n 0000262637 00000 n 0000258970 00000 n 0000256935 00000 n 0000262386 00000 n 0000259256 00000 n 0000259417 00000 n 0000259578 00000 n 0000259739 00000 n 0000328684 00000 n 0000320196 00000 n 0000328522 00000 n 0000259900 00000 n 0000260066 00000 n 0000260232 00000 n 0000260398 00000 n 0000260562 00000 n 0000260728 00000 n 0000260894 00000 n 0000261059 00000 n 0000261225 00000 n 0000261391 00000 n 0000261557 00000 n 0000261722 00000 n 0000261888 00000 n 0000262055 00000 n 0000262221 00000 n 0000267967 00000 n 0000264867 00000 n 0000262776 00000 n 0000267592 00000 n 0000265121 00000 n 0000265287 00000 n 0000265453 00000 n 0000265618 00000 n 0000265784 00000 n 0000265950 00000 n 0000266117 00000 n 0000266282 00000 n 0000266448 00000 n 0000266615 00000 n 0000266781 00000 n 0000266947 00000 n 0000267114 00000 n 0000267779 00000 n 0000267275 00000 n 0000267904 00000 n 0000267433 00000 n 0000301918 00000 n 0000270811 00000 n 0000270310 00000 n 0000268078 00000 n 0000270432 00000 n 0000270557 00000 n 0000270684 00000 n 0000319050 00000 n 0000308229 00000 n 0000318889 00000 n 0000412335 00000 n 0000272797 00000 n 0000272487 00000 n 0000270950 00000 n 0000272609 00000 n 0000272672 00000 n 0000275396 00000 n 0000274956 00000 n 0000272908 00000 n 0000275078 00000 n 0000275142 00000 n 0000275269 00000 n 0000278793 00000 n 0000277924 00000 n 0000275535 00000 n 0000278046 00000 n 0000278169 00000 n 0000278294 00000 n 0000278418 00000 n 0000278543 00000 n 0000278668 00000 n 0000282460 00000 n 0000281154 00000 n 0000278891 00000 n 0000281635 00000 n 0000281699 00000 n 0000281824 00000 n 0000281951 00000 n 0000282078 00000 n 0000282205 00000 n 0000281304 00000 n 0000282332 00000 n 0000281470 00000 n 0000285888 00000 n 0000284834 00000 n 0000282599 00000 n 0000285135 00000 n 0000285198 00000 n 0000285322 00000 n 0000285448 00000 n 0000285574 00000 n 0000285699 00000 n 0000284976 00000 n 0000301981 00000 n 0000289598 00000 n 0000287944 00000 n 0000285986 00000 n 0000289088 00000 n 0000288126 00000 n 0000288287 00000 n 0000288446 00000 n 0000288606 00000 n 0000288767 00000 n 0000288928 00000 n 0000289279 00000 n 0000289407 00000 n 0000289534 00000 n 0000412452 00000 n 0000294267 00000 n 0000291129 00000 n 0000289737 00000 n 0000294017 00000 n 0000291391 00000 n 0000291556 00000 n 0000291722 00000 n 0000291888 00000 n 0000292048 00000 n 0000292214 00000 n 0000292380 00000 n 0000292541 00000 n 0000292701 00000 n 0000292868 00000 n 0000293034 00000 n 0000293200 00000 n 0000293365 00000 n 0000293524 00000 n 0000293685 00000 n 0000293851 00000 n 0000298646 00000 n 0000296376 00000 n 0000294378 00000 n 0000298070 00000 n 0000296582 00000 n 0000296747 00000 n 0000296914 00000 n 0000297079 00000 n 0000297246 00000 n 0000297412 00000 n 0000297578 00000 n 0000297743 00000 n 0000297909 00000 n 0000298198 00000 n 0000298326 00000 n 0000298454 00000 n 0000298582 00000 n 0000302044 00000 n 0000300196 00000 n 0000298785 00000 n 0000301668 00000 n 0000301792 00000 n 0000300386 00000 n 0000301855 00000 n 0000300552 00000 n 0000300737 00000 n 0000307486 00000 n 0000302245 00000 n 0000307324 00000 n 0000300922 00000 n 0000301108 00000 n 0000301295 00000 n 0000301482 00000 n 0000307958 00000 n 0000307748 00000 n 0000319753 00000 n 0000319447 00000 n 0000329257 00000 n 0000328957 00000 n 0000331852 00000 n 0000331824 00000 n 0000348381 00000 n 0000347986 00000 n 0000357399 00000 n 0000357099 00000 n 0000364559 00000 n 0000364263 00000 n 0000368209 00000 n 0000368047 00000 n 0000378289 00000 n 0000377961 00000 n 0000381003 00000 n 0000380741 00000 n 0000389461 00000 n 0000389113 00000 n 0000392968 00000 n 0000392850 00000 n 0000395407 00000 n 0000395145 00000 n 0000400518 00000 n 0000400302 00000 n 0000411833 00000 n 0000411475 00000 n 0000412553 00000 n 0000412631 00000 n 0000416583 00000 n 0000418961 00000 n 0000419000 00000 n 0000419038 00000 n 0000419168 00000 n trailer << /Size 515 /Root 513 0 R /Info 514 0 R /ID [<1784B550E045DD0920A5548BA7339155> <1784B550E045DD0920A5548BA7339155>] >> startxref 419523 %%EOF nsd-4.1.26/doc/LICENSE0000664000175000017500000000273712275161154013615 0ustar wouterwouterCopyright (c) 2001-2006, NLnet Labs. All rights reserved. This software is open source. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the NLNET LABS nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nsd-4.1.26/doc/README0000664000175000017500000006632713401455025013470 0ustar wouterwouter1.0 Introduction 1.1 ... Basic theory of operation 1.2 ... Quick build & install 2.0 Building nsd 2.1 ... Unpacking the source 2.2 ... Configuring NSD 2.3 ... Building 2.4 ... Installing 3.0 Running NSD 3.1 ... Logging 3.2 ... AXFR access 3.3 ... Using TSIG 3.4 ... Zone expiry of secondary zones 3.5 ... Diagnosing NSD log entries 3.6 ... Interfaces 4.0 Support and Feedback 4.1 ... Your Support 1.0 Introduction This is NSD Name Server Daemon (NSD) version 4.1.26. The NLnet Labs Name Server Daemon (NSD) is an authoritative RFC compliant DNS nameserver. It was first conceived to allow for more genetic diversity for DNS server implementations used by the root-server system and it has been developed for operations in environments where speed, reliability, stability, and security are of high importance. NSD is currently used on root servers such as k.root-servers.net and is also in use by several top-level domain registries. NSD is a complete implementation of an authoritative DNS name server. For further information about what NSD is and what NSD is not please consult the REQUIREMENTS document which is a part of this distribution. If you are a BIND user (the named daemon) consult NSD_FOR_BIND_USERS. The source code is available for download from: http://www.nlnetlabs.nl/downloads 1.1 Basic Theory of Operation NSD consists of two programs: the zone compiler 'zonec' and the name server 'nsd' itself. The name server works with an intermediate database prepared by the zone compiler from standard zone files. For NSD operation this means that zones have to be compiled by zonec before NSD can use them. All this can be controlled via rc.d (SIGTERM, SIGHUP) or nsd-control, and uses a simple configuration file 'nsd.conf'. 1.2 Quick build and install Step 1: Unpack the source with gtar -xzvf nsd-4.1.26.tar.gz Step 2: Create user nsd or any other unprivileged user of your choice. In case of later make sure to use --with-user= while running configure. You can also set "username: " in the nsd.conf file later. Install openssl and libevent. Step 3: ./configure Step 4: make all (or simply 'make'). Step 5: make install Step 6: Create and edit /etc/nsd/nsd.conf file possibly from nsd.conf.sample template that comes with the distribution. (installed by default at /etc/nsd/nsd.conf.sample) Here you need to configure the zones you want to serve. TSIG keys used for secure zone transfers must be included. Also server parameters can be set, see nsd.conf(5) man page. If you have a NSD 2 nsd.zones config file take a look at the python script contrib/nsd.zones2nsd.conf, it will convert zone and TSIG key settings for you. Step 7: Copy necessary master zone files into appropriate directories under /etc/nsd/primary & /etc/nsd/secondary. Step 8: Run nsd-control start Step 9: Test the NSD with dig, drill or host. Step 10: If you're happy add a rc.d script to start into your OS boot up sequence. The format of the rc.d startup script depends on the platform. Also stop it in the shutdown sequence. You can use SIGTERM to stop, or nsd-control stop. Step 11: If desired add 'nsd-control write' to your superuser crontab to update the zone files with the content transferred from master servers periodically, such as once per day. Got any problems or questions with the steps above? Read the rest of this file. 2.0 Building NSD 2.1 Unpacking the source Use your favorite combination of tar and gnu zip to unpack the source, for example $ gtar -xzvf nsd-4.1.26.tar.gz will unpack the source into the ./nsd-4.1.26 directory... 2.2 Configuring NSD NSD can be configured using GNU autoconf's configure script. In addition to standard configure options, one may use the following: CC=compiler Specify the C compiler. The default is gcc or cc. The compiler must support ANSI C89. CPPFLAGS=flags Specify the C preprocessor flags. Such as -I. CFLAGS=flags Specify the C compiler flags. These include code generation, optimization, warning, and debugging flags. These flags are also passed to the linker. The default for gcc is "-g -O2". LD=linker Specify the linker (defaults to the C compiler). LDFLAGS=flags Specify linker flags. LIBS=libs Specify additional libraries to link with. --enable-root-server Configure NSD as a root server. Unless this option is specified, NSD will refuse to serve the ``.'' zone as a misconfiguration safeguard. --disable-ipv6 Disables IPv6 support in NSD. --enable-checking Enable some internal development checks. Useful if you want to modify NSD. This option enables the standard C "assert" macro and compiler warnings. This will instruct NSD to be stricter when validating its input. This could lead to a reduced service level. --enable-bind8-stats Enables BIND8-like statistics. --enable-ratelimit Enables ratelimiting, based on query name, type and source. --enable-draft-rrtypes Enables draft RRtypes. --with-configdir=dir Specified, NSD configuration directory, default /etc/nsd --with-nsd_conf_file=path Pathname to the NSD configuration file, default /etc/nsd/nsd.conf --with-pidfile=path Pathname to the NSD pidfile, default is platform specific, mostly /var/run/nsd.pid --with-dbfile=path Pathname to the NSD database, default is /etc/nsd/nsd.db --with-zonesdir=dir NSD default location for master zone files, default /etc/nsd/ --with-user=username User name or ID to answer the queries with, default is nsd --with-facility=facility Specify the syslog facility to use. The default is LOG_DAEMON. See the syslog(3) manual page for the available facilities. --with-libevent=path Specity the location of the libevent library (or libev). --with-libevent=no uses a builtin portable implementation (select()). --with-ssl=path Specify the location of the OpenSSL libraries. OpenSSL 0.9.7 or higher is required for TSIG support. --with-start_priority=number Startup priority for NSD. --with-kill_priority=number Shutdown priority for NSD. --with-tcp-timeout=number Set the default TCP timeout (in seconds). Default 120 seconds. --disable-nsec3 Disable NSEC3 support. With NSEC3 support enabled, very large zones, also non-nsec3 zones, use about 20% more memory. --disable-minimal-responses Disable minimal responses. If disabled, responses are more likely to get truncated, resulting in TCP fallback. When enabled (by default) NSD will leave out RRsets to make responses fit inside one datagram, but for shorter responses the full normal response is carried. --disable-largefile Disable large file support (64 bit file lengths). Makes off_t a 32bit length during compilation. 2.3 Building Use ``make'' to create NSD and support tools. If you get errors, try to use ``gmake'' (gnu version of make), especially on old systems. If so, do a `gmake realclean` first, to remove stuff that the make call messed up. 2.4 Installing Become a superuser (if necessary) and type ``make install'' This step should install four binaries nsd - the daemon itself nsd-control-setup - a shell script that creates keys for nsd-control. nsd-control - program that connects over SSL to nsd and gives commands. nsd-checkconf - simple C program to check nsd.conf before use. Plus the manual pages and a sample configuration file. 3.0 Running NSD Before running NSD you need to create a configuration file for it. The config file contains server settings, secret keys and zone settings. The server settings start with a line with the keyword 'server:'. In the server settings set 'database: ' with the filename of the name database that NSD will use. Set 'chroot:

' to run nsd in a chroot-jail. Make sure the zone files, database file, xfrdfile, difffile and pidfile can be accessed from the chroot-jail. Set 'username: ' to an unprivileged user, for security. For example: # This is a sample configuration server: database: "/etc/nsd/nsd.db" pidfile: "/etc/nsd/nsd.pid" chroot: "/etc/nsd/" username: nsd After the global server settings to need to make entries for the zones that you wish to serve. For each zone you need to list the zone name, the file name with the zone contents, and access control lists. zone: name: "example.com" zonefile: "example.com.zone" The zonefile needs to be filled with the correct zone information for master zones. For secondary zones an empty file will suffice, a zone transfer will be initiated to obtain the slave zone contents. Access control lists are needed for zone transfer and notifications. For a slave zone list the masters, by IP address. Below is an example of a slave zone with two master servers. If a master only supports AXFR transfers and not IXFR transfers (like NSD), specify the master as "request-xfr: AXFR ". By default, all zone transfer requests are made over TCP. If you want the IXFR request be transmitted over UDP, use "request-xfr: UDP ". zone: name: "example.com" zonefile: "example.com.zone" allow-notify: 168.192.185.33 NOKEY request-xfr: 168.192.185.33 NOKEY allow-notify: 168.192.199.2 NOKEY request-xfr: 168.192.199.2 NOKEY By default, a slave will fallback to AXFR requests if the master told us it does not support IXFR. You can configure the slave not to do AXFR fallback with: allow-axfr-fallback: "no" For a master zone, list the slave servers, by IP address or subnet. Below is an example of a master zone with two slave servers. zone: name: "example.com" zonefile: "example.com.zone" notify: 168.192.133.75 NOKEY provide-xfr: 168.192.133.75 NOKEY notify: 168.192.5.44 NOKEY provide-xfr: 168.192.5.44 NOKEY You also can set the outgoing interface for notifies and zone transfer requests to satisfy access control lists at the other end: outgoing-interface: 168.192.5.69 By default, NSD will retry a notify up to 5 times. You can override that value with: notify-retry: 5 Zone transfers can be secured with TSIG keys, replace NOKEY with the name of the tsig key to use. See section 3.3. Since NSD is written to be run on the root name servers, the config file can to contain something like: zone: name: "." zonefile: "root.zone" provide-xfr: 0.0.0.0/0 NOKEY # allow axfr for everyone. provide-xfr: ::0/0 NOKEY You should only do that if you're intending to run a root server, NSD is not suited for running a . cache. Therefore if you choose to serve the . zone you have to make sure that the complete root zone is timely and fully updated. To prevent misconfiguration, NSD configure has the --enable-root-server switch, that is by default disabled. In the config file, you can use patterns. A pattern can have the same configuration statements that a zone can have. And then you can include-pattern: in a zone (or in another pattern) to apply those settings. This can be used to organise the settings. The nsd-control tool is also controlled from the nsd.conf config file. It uses SSL encrypted transport to 127.0.0.1, and if you want to use it you have to setup the keys and also edit the config file. You can leave the remote-control disabled (the secure default), or opt to turn it on: # generate keys nsd-control-setup # edit nsd.conf to add this remote-control: control-enable: yes By default nsd-control is limited to localhost, as well as encrypted, but some people may want to remotely administer their nameserver. What you then do is setup nsd-control to listen to the public IP address, with control-interface: after the control-enable statement. Furthermore, you copy the key files /etc/nsd/nsd_server.pem /etc/nsd/nsd_control.* to a remote host on the internet; on that host you can run nsd-control with -c which references same IP address control-interface and references the copies of the key files with server-cert-file, control-key-file and control-cert-file config lines after the control-enable statement. The nsd-server authenticates the nsd-control client, and also the nsd-control client authenticates the nsd-server. When you are done with the configuration file, check the syntax using nsd-checkconf The zone files are read by the daemon, which builds 'nsd.db' with their contents. You can start the daemon with nsd or with "nsd-control start" (which execs nsd again). or with nsd -c To check if the daemon is running look with ps, top, or if you enabled nsd-control, nsd-control status To reload changed zone files after you edited them, without stopping the daemon, use this to check if files are modified: kill -HUP `cat ` If you enabled nsd-control, you can reread with nsd-control reload With nsd-control you can also reread the config file (new zones, ..) nsd-control reconfig To restart the daemon /etc/rc.d/nsd restart # or your system(d) equivalent To shut it down (for example on the system shutdown) do kill -TERM or nsd-control stop NSD will automatically keep track of secondary zones and update them when needed. When primary zones are updated and reloaded notifications are sent to slave servers. The zone transfers are applied to nsd.db by the daemon. To write changed contents of the zone files for slave zones to disk in the text-based zone file format, issue nsd-control write. NSD will send notifications to slave zones if a master zone is updated. NSD will check for updates at master servers periodically and transfer the updated zone by AXFR/IXFR and reload the new zone contents. If you wish exert manual control use nsd-control notify, transfer and force_transfer commands. The transfer command will check for new versions of the secondary zones hosted by this NSD. The notify command will send notifications to the slave servers configured in 'notify:' statements. 3.1 Logging NSD doesn't do any logging. We believe that logging is a separate task and has to be done independently from the core operation. This consciously is not part of nsd itself in order to keep nsd focused and minimize its complexity. It is better to leave logging and tracing to separate dedicated tools. dnsstat can also easily be configured and/or modified to suit local statistics requirements without any danger of affecting the name server itself. We have run dnsstat on the same machine as nsd, we would recommend using a multiprocessor if performance is an issue. Of course it can also run on a separate machine that has MAC layer access to the network of the server. The nsd-control tool can output some statistics, with nsd-control stats and nsd-control stats_noreset. In contrib/nsd_munin_ there is a munin grapher plugin that uses it. The output of nsd-control stats is easy to read (text only) with scripts. The output values are documented on the nsd-control man page. The CAIDA dnsstat tool referenced is recommended to nsd operators as a means of keeping statistics and check on abnormal query loads. http://www.caida.org/tools/utilities/dnsstat/dnsstat-3.5.1a.tar.gz Another tool is the dnstop, that displays DNS statistics on your network. http://dns.measurement-factory.com/tools/dnstop/src/dnstop-20060517.tar.gz A sample invocation of dnsstat: /usr/local/Coral/bin/crl_dnsstat -D -Ci=60 -Cd=240 -C'filter dst 10.1.1.3' -h -u if:fxp1 A sample output of a slightly modified version: # dnsstat output version: 0.2 "dfk" # begin trace interval at 1025267664.859043, duration 15.000000 # DNS messages: 74973 (4998.200000/s); DNS queries: 151983 (10132.200000/s) # print threshold: 30 messages/sec #src op type class queries msgs rd notes 208.18.162.10 - - - 533 533 0 " 0 MX IN 6 " 0 A IN 264 " 0 ANY IN 263 209.11.18.248 - - - 661 661 0 " 0 A IN 655 " 0 MX IN 6 210.117.65.137 - - - 745 745 0 " 0 A IN 745 216.54.221.131 - - - 477 477 0 " 0 A IN 477 193.97.205.80 - - - 681 681 0 " 0 A IN 3 " 0 ANY IN 678 168.30.240.11 - - - 685 685 0 " 0 A IN 405 " 0 MX IN 280 210.94.6.67 - - - 742 742 0 " 0 A IN 742 63.66.68.237 - - - 1375 1375 0 " 0 A IN 1375 168.30.240.12 - - - 493 493 0 " 0 A IN 493 139.142.205.225 - - - 5579 5579 0 " 0 A IN 3006 " 0 MX IN 2573 210.117.65.2 - - - 700 700 0 " 0 A IN 700 # end trace interval 3.2 AXFR access The access list for AXFR should be set with provide-xfr: in the nsd config file. This is per zone. See nsd.conf(5). For example to grant zone 'example.com' AXFR right to localhost for IPv4 and IPv6, use the below config options. zone: name: "example.com" provide-xfr: 127.0.0.1 NOKEY provide-xfr: ::1 NOKEY You can use dig @localhost example.com axfr to test this. 3.3 Using TSIG NSD supports TSIG for any query to the server, for zone transfer and for notify sending and receiving. TSIG keys are based on shared secrets. These must be configured in the config file. To keep the secret in a separate file use include: "filename" to include that file. An example tsig key named sec1_key. key: name: "sec1_key" algorithm: hmac-md5 secret: "6KM6qiKfwfEpamEq72HQdA==" This key can then be used for any query to the NSD server. NSD will check if the signature is valid, and if so, return a signed answer. Unsigned queries will be given unsigned replies. The key can be used to restrict the access control lists, for example to only allow zone transfer with the key, by listing the key name on the access control line. # provides AXFR to the subnet when TSIG is used. provide-xfr: 10.11.12.0/24 sec1_key # allow only notifications that are signed allow-notify: 192.168.0.0/16 sec1_key If the TSIG key name is used in notify or request-xfr lines, the key is used to sign the request/notification messages. 3.4 Zone expiry of secondary zones NSD will keep track of the status of secondary zones, according to the timing values in the SOA record for the zone. When the refresh time of a zone is reached, the serial number is checked and a zone transfer is started if the zone has changed. Each master server is tried in turn. Master zones cannot expire. They are always served. Zones are master zones if they have no 'request-xfr:' statements in the config file. After the expire timeout (from the SOA record at the zone apex) is reached, the zone becomes expired. NSD will return SERVFAIL for expired zones, and will attempt to perform a zone transfer from any of the masters. After a zone transfer succeeds, or if the master indicates that the SOA serial number is still the same, the zone will be OK again. In contrast with e.g. BIND, the inception time for a slave zone is stored on disk (in the xfrdfile: "xfrd.state"), together with timeouts. If a slave zone acquisition time is recent enough, this means that NSD can start serving a zone immediately on loading, without querying the master server. If your slave zone has expired, and no masters can be reached, but you still want NSD to serve the zone. (i.e. ''My network is in shambles, but serve the zone dangit!''). You can delete the file 'xfrd.state', but leave the zonefile for the zone intact. Make sure to stop nsd before you delete the file, as NSD writes it on exit. Upon loading NSD will treat the zonefile that you as operator have provided as recent and will serve the zone. Even though NSD will start to serve the zone immediately, the zone will expire after the timeout is reached again. NSD will also attempt to confirm that you have provided the correct data by polling the masters. So when the master servers come back up, it will transfer the updated zone within seconds. In general it is possible to provide zone files for both master and slave zones manually (say from email or rsync). Reload with SIGHUP or nsd-control reload to read the new zonefile contents into the name database. When this is done the new zone will be served. For master zones, NSD will issue notifications to all configured 'notify:' targets. For slave zones the above happens; NSD attempts to validate the zone from the master (checking its SOA serial number). 3.5 Diagnosing NSD log entries NSD will print log messages to the system log (or 'logfile:' configuration entry). Some of these messages are discussed below. These messages can get extra support if errors happen. - "Reload process failed with status , continuing with old database" This log message indicates the reload process of NSD has failed for some reason. The reason can be anything from a missing database file to internal errors. If this happens often, please let us know, this error message can be caught in the code, and appropriate action could be taken. We are as of yet not sure what action is appropriate, if any. - "snipping off trailing partial part of " Please let us know if, and how often, this happens. What happens is the file ixfr.db contains only part of expected data. The corruption is removed by snipping off the trailing part. - "memory recyclebin holds bytes" This is printed for every reload. NSD allocates and deallocates memory to service IXFR updates. The recyclebin holds deallocated memory ready for future use. If the number grows too large, a restart resets it. - "xfrd: max number of tcp connections (32) reached." This line is printed when more than 32 zones need a zone transfer at the same time. The value is a compile constant (xfrd-tcp.h), but if this happens often for you, we could make this a config option. NSD will reuse existing TCP connections to the same master (determined by IP address) to transfer up to 64k zones from that master. Thus this error should only happen with more than 32 masters or more than 64*32=2M zones that need to be updated at the same time. If this happens, more zones have to wait until a zone transfer completes (or is aborted) before they can have a zone transfer too. This waiting list has no size limit. - "error: NSEC3PARAM entry has unknown hash algo " This error means that the zone has NSEC3 chain(s) with hash algorithms that are not supported by this version of NSD, and thus cannot be served by NSD. If there are also no NSECs or NSEC3 chain(s) with known hash algorithms, NSD will not be able to serve DNSSEC authenticated denials for the zone. 3.6 Interfaces NSD will by default bind itself to the system default interface and service ip4 and if available also ip6. It is possible to service only ip4 or ip6 using the -4, -6 commandline options, or the ip4-only and ip6-only config file options. The commandline option -a and config file option ip-address can be given to bind to specific interfaces. Multiple interfaces can be specified. This is useful for two reasons: o The specific interface bound will result in the OS bypassing routing tables for the interface selection. This results in a small performance gain. It is not the performance gain that is the problem, sometimes the routing tables can give the wrong answer, see the next point. o The answer will be routed via the interface the query came from. This makes sure that the return address on the DNS replies is the same as the query was sent to. Many resolvers require the source address of the replies to be correct. The ip-address: option is easier than configuring the OS routing table to return the DNS replies via the correct interface. The above means that even for systems with multiple interfaces where you intend to provide DNS service to all interfaces, it is prudent to specify all the interfaces as ip-address config file options. With the config file option ip-transparent you can allow NSD to bind to non local addresses. 4.0 Support and Feedback NLnet Labs is committed to support NSD and its other software products on a best effort basis, free of charge. This form of community support is offered through a mailing lists and the 'bugzilla' web interface. http://www.nlnetlabs.nl/bugs/ If for any reason NLnet Labs would stop community support of NSD such would be announced on our web pages at least two years in advance. The community mailing list nsd-users@nlnetlabs.nl can be used to discuss issues with other users of NSD. Subscribe here http://open.nlnetlabs.nl/mailman/listinfo/nsd-users NLnet Labs recognizes that in some corporate environments this commitment to community support is not sufficient and that support needs to be codified. We therefore offer paid support contracts that come in 3 varieties. More information about these support varieties can be found at Alternatively you can contact mailto:nsd-support@nlnetlabs.nl . Support goes two ways. By acquiring one of the support contracts you also support NLnet Labs to continue to participate in the development of the Internet architecture. We do this through our participation in the (IETF) standards process and by developing and maintaining reference implementations of standards and tools to support operation and deployment of new and existing Internet technology. We are interested in our users and in the environment you use NSD. Please drop us a mail when you use NSD. Indicate in what kind of operation you deploy NSD and let us know what your positive and negative experiences are. http://www.nlnetlabs.nl/nsd and mailto:nsd-info@nlnetlabs.nl 4.1 Your Support NLnet Labs offers all of its software products as open source, most are published under a BSD license. You can download them, not only from the NLnet Labs website but also through the various OS distributions for which NSD, ldns, and Unbound are packaged. We therefore have little idea who uses our software in production environments and have no direct ties with 'our customers'. Therefore, we ask you to contact us at users@NLnetLabs.nl and tell us whether you use one of our products in your production environment, what that environment looks like, and maybe even share some praise. We would like to refer to the fact that your organization is using our products. We will only do that if you explicitly allow us. In all other cases we will keep the information you share with us to ourselves. In addition to the moral support you can also support us financially. NLnet Labs is a recognized not-for-profit charity foundation that is chartered to develop open-source software and open-standards for the Internet. If you use our software to satisfaction please express that by giving us a donation. For small donations PayPal can be used. For larger and regular donations please contact us at users@NLnetLabs.nl. Also see http://www.nlnetlabs.nl/labs/contributors/. $Id: README 4690 2016-08-22 10:38:14Z wouter $ nsd-4.1.26/doc/coding-style0000664000175000017500000000056010443534063015122 0ustar wouterwouterCoding Style for NSD [This is incomplete, but a start] o No space after function/keyword o { on the same line as the if/while/for statement o If an 'if' has one statement in the 'then' part omit the braces: if (!x) return NULL; Indent the 'then' part with tabs o Function: return-type functionname(parameters, ...) { ... } nsd-4.1.26/doc/CREDITS0000664000175000017500000000452012166776123013627 0ustar wouterwouterThe NSD was primarily developed by NLnet Labs on request from and close cooperation with RIPE NCC, as an alternative name server software to be run on the root name server RIPE NCC operates. Below is the NSD team (nsd-team@nlnetlabs.nl) in alphabetical order: Alexis Yushin, NLnet Labs - design and implementation for NSD 1.0.x and 1.1.x. Erik Rozendaal, NLnet Labs - design and implementation for NSD 1.2.x and later. Daniel Karrenberg, RIPE NCC - design, major testing and bug reports Jaap Akkerhuis, SIDN NL - consultancy, advice and company :) Jelte Jansen, NLnet Labs - testing, patches, advice, NSD 3 Matthijs Mekking, NLnet Labs - testing, patches, maintenance, NSD 3 Miek Gieben, NLnet Labs - testing, patches, zone compiler, NSD 2 Olaf Kolkman, RIPE NCC - protocol purist, design, perl test implementation Ronald van der Pol, NLnet Labs - code review, MacOS X portability, IPv6. Ted Lindgreen, NLnet Labs - design, code review, testing Wouter Wijngaards, NLnet Labs - design and implementation for NSD 3 and NSD 4. Contributors (in alphabetical order): Aaron Glenn - DragonflyBSD, BSD/sparc64 testing. Ben Laurie - NSEC3 patch. Bin Zhang - NSD 3 prerelease testing. Colm MacCárthaigh, - IPv6 binding and cleanups. Farkas Levente - rpm specfile improvements. Jakob Schlyter, Kirei - chroot and several other patches Jun-ichiro itojun Hagino, IIJLab - IPv6 transport Kai - NSD 3 prerelease testing. Mans Nilsson - (Solaris) Testing Markus Heimhilcher - .AT zones for testing Martin Svec - Optimalization patches. Matthew Smith - NetBSD testing. Ondrej Sury - nsd-notify.8 man page Paul Wouters - zone compiler testing Peter Hessler - OpenBSD, amd64 testing. Stephane Bortzmeyer - Tru64 portability. Config conversion. nsd-4.1.26/doc/ChangeLog0000664000175000017500000044405113377730333014366 0ustar wouterwouter29 November 2018: Wouter - Tag for 4.1.26rc1. 27 November 2018: Wouter - Fix parsezone failure in 4194 fix. 26 November 2018: Wouter - Fix to not set GLOB_NOSORT so the nsd.conf include: files are sorted and in a predictable order. - Added nsd-control changezone. nsd-control changezone name pattern allows the change of a zone pattern option without downtime for the zone, in one operation. - Fix #3433: document that reconfig does not change per-zone stats. 20 November 2018: Wouter - Fix #4205: enable-recvmmsg in mixed IPv4/IPv6 environment fails. This sets the msg_hdr.msg_namelen correctly after receipt. 19 November 2018: Wouter - Support SO_REUSEPORT_LB in FreeBSD 12 with the reuseport: yes option in nsd.conf. - Fix #4202: nsd-control delzone incorrect exit code on error. - Tab style fix to use tab for 8 spaces, from Xiaobo Liu. 25 October 2018: Wouter - Adjust dnstap socket path for chroot. 22 October 2018: Wouter - Fix #4194: Zone file parser derailed by non-FQDN names in RHS of DNSSEC RRs. - Fix some more, neater code and checks for domain length limit. - check that the dnstap socket file can be opened and exists, print error if not. 4 October 2018: Wouter - dnstap work, the dnstap.proto is a copy of the file from Unbound, also dnstap.m4 configure include file. - dnstap collector: free eventbase and memclean nicer. - dnstap collector: send data and read it in collector. - dnstap/dnstap.c and .h from Unbound's contribution from Farsight Security, added to then adapt it for dnstap logging in NSD. - dnstap.c with auth query and auth response, and called from the collector. - dnstap work, config nsd.conf parse. - dnstap example config. 25 September 2018: Wouter - NSD 4.1.25 released, trunk has 4.1.26 in development. 18 September 2018: Wouter - tag for NSD 4.1.25rc1. 17 September 2018: Wouter - Fix #4156: Fix systemd service manager state change notification 14 September 2018: Wouter - Remove unused if clause during server service startup. 13 September 2018: Wouter - Fix typo in clang analysis test. - Annotate exit functions with noreturn. - nsd-control prints neater errors for file failures. 12 September 2018: Wouter - clang analysis test. 11 September 2018: Wouter - Fix to combine the same error function into one, from Xiaobo Liu. - Fix initialisation in remote.c. - please clang analyzer and fix parse of IPSECKEY with bad gateway. - Fix unit test code for clang analyzer. - Fix nsd-checkconf fail on bad zone name. 10 September 2018: Wouter - Fix coding style in nsd.c 7 September 2018: Wouter - append_trailing_slash has one implementation and is not repeated differently. 4 September 2018: Wouter - Fix codingstyle in nsd-checkconf.c in patch from Sharp Liu. 15 August 2018: Wouter - Fix use_systemd typo/leftover in remote.c. 13 August 2018: Wouter - tag for 4.1.24 release. - trunk is 4.1.25 in development. - Fix that nsec3 precompile deletion happens before the RRs of the zone are deleted. - Fix printout of accepted remote control connection for unix sockets. 6 August 2018: Wouter - tag for 4.1.24rc1 release. 30 July 2018: Wouter - Tag for NSD 4.1.23 release, trunk is 4.1.24, includes fix NSD time sensitive TSIG compare vulnerability. - Fix checkconf test for use-systemd option. 25 July 2018: Wouter - #4133: Fix that when IXFR contains a zone with broken NSEC3PARAM chain, NSD leniently attempts to find a working NSEC3PARAM. 23 July 2018: Wouter - Remove socket activation from systemd code, it was reported as not useful to enable. The readiness signalling is still there, and can be enabled with use-systemd: yes. - Only call sd_notify from systemd when use-systemd is yes. 6 July 2018: Wouter - RFC8162 support, for record type SMIMEA. - Fix that type CAA (and URI) in the zone file can contain dots when not in quotes. 26 June 2018: Wouter - configure --enable-systemd (needs pkg-config and libsystemd) can be used to then use-systemd: yes in nsd.conf and use socket activation and readiness signalling with systemd. 19 June 2018: Wouter - #4106: Fix that stats printed from nsd-control are recast from unsigned long to unsigned (remote.c). 14 June 2018: Wouter - Fix that first control-interface determines if TLS is used. Warn when IP address interfaces are used without TLS. 12 June 2018: Wouter - #4102: control interface via local socket. configure it with control-interface: "/path/nsd.ctl" The path has to start with a / to separate it from an IP address. The local socket does not use SSL, but unencrypted traffic, use file and containing directory permissions to restrict access. 6 June 2018: Wouter - Patch to fix openwrt for mac os build darwin detection in configure. 4 June 2018: Wouter - tag for 4.1.22rc1. Became 4.1.22 on 11 June, trunk is 4.1.23 in development from this point. 31 May 2018: Wouter - Fix to use same condition for nsec3 hash allocation and free. 23 May 2018: Wouter - Use accept4 to speed up answer of TCP queries, on Linux and FreeBSD and OpenBSD. 22 May 2018: Wouter - Fix nsec3 hash of parent and child co-hosted nsec3 enabled zones. 15 May 2018: Wouter - Fix memory free in unit test. 14 May 2018: Wouter - Tag for 4.1.21 release. - trunk has 4.1.22 in development. - refuse-any sends truncation (+TC) in reply to ANY queries over UDP, and allows TCP queries like normal. 7 May 2018: Wouter - Tag for 4.1.21rc1 release. 4 May 2018: Wouter - Fix #4093: Release notes not using 2018. 3 May 2018: Wouter - Fix buffer size warnings from compiler on filename lengths. 26 April 2018: Wouter - lower memory usage for tcp connections, so tcp-count can be higher. - Fix checkconf test for refuse-any option. 3 April 2018: Wouter - refuse-any nsd.conf option that refuses queries of type ANY. 5 March 2018: Wouter - Fix #3562: explain build error when flex missing. 20 February 2018: Wouter - For more clang warnings - Fix spelling error in xfr-inspect. 19 February 2018: Wouter - Fix for clang analysis complaints. 15 February 2018: Wouter - --enable-memclean cleans up memory for use with memory checkers, eg. valgrind. - Fix unused variable warnings from clang analyzer. 14 February 2018: Wouter - updated RELNOTES for upcoming release. - tag 4.1.20rc1, became release on 20 feb, trunk has 4.1.21 in development. 9 February 2018: Wouter - make depend: updated the make dependencies in the Makefile. 8 February 2018: Wouter - Fix memory leak when rehashing nsec3 after axfr or zonefile read, in the selectively allocated precompiled nsec3 hashes. 6 February 2018: Wouter - Fix memory leak in zone file read of unknown rr formatted RRs. 11 December 2017: Wouter - Add test for support of -Wno-address-of-packed-member for --enable-packed. - tag for release 4.1.19 - trunk has 4.1.20 in development. 8 December 2017: Wouter - tag for 4.1.19rc1 7 December 2017: Wouter - Fixup lexer warning for gcc 4.2. 6 December 2017: Wouter - Fix 3392: Fix regression in 4.1.18 for notify lists with ip4 and ip6 targets. 5 December 2017: Wouter - Fix spelling error in xfr-inspect. 1 December 2017: Wouter - Fix warnings emitted by clang for --enable-packed. Alignment is not a problem for x86_64, don't enable packed when the platform requires aligned access. 30 November 2017: Wouter - tag for 4.1.18 release. - trunk has 4.1.19 in development. - ignore fallthrough compiler warning in flex EOF rule. 27 November 2017: Wouter - Fix crash for DS query when parent and child zones both configured in nsd.conf and parent zone has not loaded properly. - tag for 4.1.18rc2. 16 November 2017: Wouter - tag for 4.1.18rc1. 14 November 2017: Wouter - Fix #2871: Increase number of sockets for xfrd transfers. 6 November 2017: Wouter - Set usage counts in namedb tree to uint32 to save memory. - Fix up debug content from nsec3 collision printout work. 2 November 2016: Wouter - make ip-transparent option work on OpenBSD. 11 October 2016: Wouter - Fix #1567: Change crit to err log level for gettimeofday failure. Add defines for compile without syslog. 9 October 2016: Wouter - Fix collision printout of nsec3 to print name, hash and reverse. 2 October 2016: Wouter - nsd-control zonestatus prints wait time between attempts, for zones that are in that waiting time. 19 September 2016: Wouter - merges feature branch branches/alloced_prehashes into trunk. 18 September 2016: Wouter - Fix #1446: A corrupted zone file "propagates" to good ones. 14 September 2016: Wouter - Fix layout in xfrd.c. 6 September 2017: Willem - Save memory by selectively allocate precompiled nsec3 hashes 29 August 2016: Wouter - With --enable-packed save memory, at expense of unaligned reads. - Fix writev compile warning on FreeBSD. 25 July 2016: Wouter - NSD sends up to 16 notifies simultaneously for up to 64 zones, to increase rate of notification for large master configurations. 24 July 2016: Wouter - Fix gcc 7.1.1 warnings. 17 July 2016: Wouter - Trunk has 4.1.18 - xfr-inspect is part of source dir, but not made or installed by default. - retry timeout between sending notifies dropped from 15 to 3 sec. 13 July 2016: Wouter - tag 4.1.17rc1, and that became the 4.1.17 release on 21 July 2017. 29 June 2016: Wouter - make depend. 26 June 2016: Wouter - Fix text format of deletes for CDS and CDNSKEY, single 0 to represent empty base64 or hex string. 23 June 2016: Wouter - Fix potential null pointer in nsec3 adjustment tree. 15 June 2016: Wouter - xfr-inspect debug tool prints out xfr contents of files in tmp. 6 June 2016: Wouter - Fix #1272: use writev to put tcp length field with data for outgoing zone transfer requests. 16 May 2016: Wouter - zone parser parses type AVC (it has TXT format). 25 April 2016: Wouter - 4.1.16 release tag. - trunk contains 4.1.17 in development. 11 April 2016: Wouter - 4.1.16 rc1 tag for release. - minor manpage fix. 5 April 2016: Wouter - Patch for expire state in multi-master when masters includes broken master. 27 March 2016: Wouter - Fix 1243: Option to make NSD emit really minimal responses, minimal-responses: yes in nsd.conf. - but they give additional information for priming queries (type NS). 6 March 2016: Wouter - Fix 1228: OpenSSL include is not guarded with HAVE_SSL 28 February 2016: Wouter - Printout serial error with hint it may be too big. 20 February 2016: Wouter - Fix missing _t to _type conversion for disable-radix-tree option. 15 February 2016: Wouter - zone parser can parse acronyms for algorithms ED25519 and ED448. 13 February 2016: Wouter - Calculate new udb index after growing the array, fix from Chaofeng Liu. 7 February 2016: Wouter - tag for 4.1.15 rc1. Which became 4.1.15 on 16 Feb. Trunk 4.1.16. 19 January 2016: Wouter - Fix to rename _t typedefs because POSIX reserves them. 3 January 2016: Wouter - Fix #1195: Fix so that NSD fails on non-compliant values for Serial. 14 December 2016: Wouter - Squelch zone transfer error address family not supported by protocol at low verbosity levels. 13 December 2016: Wouter - Fix nsd-control and ipv6 only. 8 December 2016: Wouter - tag 4.1.14 - trunk contains 4.1.15 in development. 1 December 2016: Wouter - Fix restart of zone transfers when new config becomes available. - tag 4.1.14rc1 25 October 2016: Wouter - Fix #1132 for SERVFAIL zones perform backoff, and remembers the timeout on next startup. - Save backoff timeout into xfrd.state file, this file has a higher version number now. Old files are skipped silently (causes refresh) and created as new files upon exit. - Set number of rounds to 1; NSD will try every master once, then wait for timeout or notify. - Fix axfr fallback for rounds to 1. 20 October 2016: Wouter - suppress compile warning in lex files. 18 October 2016: Wouter - Robust fix against missing master in tcp_open for xfrd. - More in depth fix for the previous. - Fix wildcards in include: config statements with chroot enabled. 27 September 2016: Wouter - NSD 4.1.13 tag. - trunk has 4.1.14 in development. - Fix null memcpy for radixtree with single link element. 19 September 2016: Wouter - Review comments Ralph: wrapped long lines and nicer example conf. 16 September 2016: Wouter - NSD 4.1.13rc1 tag. 15 September 2016: Wouter - Test for openssl init_crypto and init_ssl functions. 14 September 2016: Ralph - Fix OPENSSL_INIT_ADD_ALL_DIGESTS compatibility check 13 September 2016: Wouter - Fix double const in dname_const() function. - Silenced flex-generated sign-unsigned warning print with gcc diagnostic pragma. 8 September 2016: Wouter - more extensible edns option handling. 2 September 2016: Wouter - Release of 4.1.12; trunk is 4.1.13 and the patch for 4.1.12 (that does not contain the other changes to the trunk) is folded into the trunk. - Fix #827: fix compile with openssl 1.1.0 with api=1.1.0. 25 August 2016: Wouter - Fix multimaster for not tried full zone transfer for a expired zone. - Explain --disable-radix tree uses some more CPU. 22 August 2016: Wouter - Fix README spelling error of BSD license (reported by Joerg Jung). 19 August 2016: Wouter - for type SRV add A/AAAA to the additional section (if possible), just like we already do for type MX. 17 August 2016: Wouter - Add robustness against unallocated data in nsec3 trees. 16 August 2016: Wouter - configure --disable-radix-tree for about 15% lower memory usage. 12 August 2016: Wouter - Fix #817: xfrd update failed loop. 9 August 2016: Wouter - Can config key algorithms with the digest name, eg. 'sha256'. - default tsig algorithm is sha256. - Fix typo in log output, 'transfered' -> 'transferred'. - Fix compile warnings about signcompare in minmax retrytime. 8 August 2016: Wouter - Support syntax of RR type OPENPGPKEY from RFC 7929. 5 August 2016: Wouter - multi-master-check: yes can be used to check all masters for the last version, using the higher version from the configured masters, from Manabu Sonoda. - small fixups on patch. And fix spacing and remove configure flag. - Fix #812: make depend fails after distribution. 2 August 2016: Wouter - Fix unused result warnings from write and strtol. 1 August 2016: Wouter - Tag 4.1.11rc1. - Fix nsec3 missing for nsec3 signed parent and child for DS at zonecut. - Tag 4.1.11rc2. - trunk is 4.1.12 in development. 8 July 2016: Wouter - Note down tracking numbers for issue JVN#63359718 JPCERT#91251865. 5 July 2016: Wouter - Fix #790: size-limit-xfr can stop NSD from downloading infinite zone transfer data size, from Toshifumi Sakaguchi. 27 June 2016: Wouter - Set default for min-refresh-time and min-retry-time to 0. Behaves just like before, but has a configurable option in nsd.conf. - Fix #783: Trying to run a root server without having configured it silently gives wrong answers. 16 June 2016: Wouter - When tcp is more than half full, use short timeout for tcp session. - Patch for {max,min}-{refresh,retry}-time from YAMAGUCHI Takanori. - man page entries for max-refresh-time patch. 15 June 2016: Wouter - Fix build without IPv6, patch from Zdenek Kaspar. 14 June 2016: Wouter - release 4.1.10 and tag for that. - trunk has 4.1.11 in development. 7 June 2016: Wouter - Fix NSEC3 ent fix to use closest encloser, not wildcard denial. 2 June 2016: Wouter - Fix for NSEC3 with zone signed without exact match for empty nonterminals, the answer for that domain gets wildcard denial. - #772 Document that recvmmsg has IPv6 problems on some linux kernels. - tag for 4.1.10rc1. 31 May 2016: Wouter - print notice that nsd is starting before taking off. 20 May 2016: Wouter - Updated fix for nonterminal nsec3 answers. 19 May 2016: Wouter - Fix empty nonterminal nsec3 cover answers. 12 May 2016: Wouter - NSD includes AAAA before A for queries over IPV6 (in delegations). And TC is set if no glue can be provided with a delegation because of packet size. 19 April 2016: Wouter - Fix #755: NSD spins after a zone update and a lot of TCP queries. 7 April 2016: Wouter - If set without nsd.db print "" as the default in the man pages. 4 April 2016: Wouter - Fix #751: NSD fails to occlude names below a DNAME. 24 March 2016: Wouter - Fix for openssl 1.1.0, HMAC_CTX size not exported from openssl. 21 March 2016: Wouter - Update acx_nlnetlabs.m4 to version 33 with HMAC_Update test. - acx_nlnetlabs.m4 to v34, with -ldl -pthread test for libcrypto. 15 March 2016: Wouter - ip-freebind: yesno option in nsd.conf sets IP_FREEBIND socket option for Linux, binds to interfaces and addresses that are down. - Change the nsd.db file version because of nanosecond precision fix. - 4.1.9 release with the nsd.db file version fix (but not freebind), trunk contains 4.1.10 in development. 10 March 2016: Wouter - Tag 4.1.8 - Trunk contains 4.1.9 in development. 2 March 2016: Wouter - Tag 4.1.8rc1 1 March 2016: Wouter - #744: Fix that NSD replies for configured but unloaded zone with SERVFAIL, not REFUSED. 16 February 2016: Wouter - RR type CSYNC (RFC7477) syntax is supported. 29 January 2016: Wouter - #739: zonefile changes when mtime is small are detected on reload, if filesystem supports precision mtime values. 19 January 2016: Wouter - Fix #736: segfault during zone transfer. 08 January 2016: Wouter - Define _DEFAULT_SOURCE with _BSD_SOURCE for recent Linuxes. 05 January 2016: Wouter - #732: tcp-mss, outgoing-tcp-mss options for nsd.conf, patch from Daisuke Higashi. 04 January 2016: Wouter - Updated acx_nlnetlabs to version 32. 11 December 2015: Wouter - Fix flto check for OSX clang. 10 December 2015: Wouter - 4.1.7 release - trunk has 4.1.8 in development. - take advantage of arc4random_uniform if available, patch from Loganaden Velvindron. 3 December 2015: Wouter - tag for 4.1.7rc1 prerelease. 2 December 2015: Wouter - configure --enable-ratelimit-default-is-off with --enable-ratelimit to set the default ratelimit to disabled but available in nsd.conf. - Document that ratelimit qps and slip are updated in reconfig. - version: "string" option to set chaos version query reply string. - Fix up defaults in manpage. 1 December 2015: Wouter - Explain rrl-slip better in documentation. 30 November 2015: Wouter - Fix TCP responses when REUSEPORT is in use by turning it off. - reuseport: no is the default, because the feature is not troublefree. - Document default in manpage for rrl-slip, ip4 and 6 prefixlength. 24 November 2015: Wouter - Fix zonec ttl mismatch printout to include more information. 18 November 2015: Wouter - RELNOTES more descriptive. - newer acx_nlnetlabs.m4. - spelling fixes from Igor Sobrado Delgado. 17 November 2015: Wouter - Fix #721: Fix wrong error code (FORMERR) returned for unknown opcode. NOTIMP expected. 16 November 2015: Wouter - Allocate less memory for TSIG digest. 6 November 2015: Wouter - Fixup for newer acx_nlnetlabs.m4, test for openssl version after testing for libdl need. 5 November 2015: Wouter - newer acx_nlnetlabs.m4, does not needlessly link with -ldl. 30 October 2015: Wouter - Fix tpkg tests for portability. 29 October 2015: Wouter - patch from Doug Hogan for SSL_OP_NO_SSLvx options. - updated contrib/nsd.spec, from Bálint Szigeti. - support configure --with-dbfile="" for nodb mode by default, where there is no binary database, but nsd reads and writes zonefiles. 27 October 2015: Wouter - portability fixes. 26 October 2015: Wouter - Init pfd for handlers added during handler-event-walk. 23 October 2015: Wouter - Fix many interfaces and zones updates from nsd parent event loop. 22 October 2015: Wouter - 4.1.6 release tag. - trunk contain 4.1.7 in development. 20 October 2015: Wouter - 4.1.6rc2 tag created. 19 October 2015: Wouter - Fix compile of zonec error message on FreeBSD. 15 October 2015: Wouter - 4.1.6rc1 tag created. 13 October 2015: Wouter - nsd-checkconf warns for master zones with no zonefile statement. - Fix start failure when many file descriptors are in use. - The servfail rcode is not printed with a space in the middle. - fixup file descriptor fixup nicer. - print failed token for config syntax error or parse error. 12 October 2015: Wouter - Fix #711: Document that debug-mode yes is used for staying attached to the supervisor console. - Document verbosity 3 prints more information. 30 September 2015: Wouter - makedist.sh print on pgp signature creation. 28 September 2015: Wouter - Fix typo in zonec.c inside error message. 24 September 2015: Wouter - Fix #701: Fix that AD=1 set in a BADVERS response. 21 September 2015: Wouter - Fix #706: default port 53 not opened on ip4 because of getaddrinfo hints initialisation failure. - 4.1.5 release tag - trunk contains 4.1.6 in development. 9 September 2015: Wouter - 4.1.4 release tag created. - trunk contains 4.1.5 in development. 31 August 2015: Wouter - 4.1.4rc1 tag created. 28 August 2015: Wouter - Fix #698 formatting errors and typos in nsd.8.in. - Add --enable-pie and --enable-relro-now options. 18 August 2015: Wouter - Admitted axfrs are logged at verbosity 1. Refused at verbosity 2. 17 August 2015: Wouter - Fixed checkconf test for reuseport setting. 14 August 2015: Wouter - SO_REUSEPORT does not work on FreeBSD. Enabled by default on Linux, not enabled by default on other OSes. 5 August 2015: Wouter - Fix that notify from nsd-control contains soa serial. 3 August 2015: Wouter - squelch SO_REUSEPORT failure on verbosity less than 3. 31 July 2015: Wouter - removed hardcoded interface limit, --with-max-ips removed. - SO_REUSEPORT support. 16 July 2015: Wouter - Fix #618: documented need to list ip-addresses separately in nsd.conf if there are multiple, because the source address of replies can otherwise go wrong. 10 July 2015: Wouter - Fix that for expired zones NSD performs an AXFR and accepts newer and older serial numbers. - Document that minimal responses only minimizes responses to fit in one datagram. It does not minimize smaller responses. 2 July 2015: Wouter - Fix NSID response for short edns sizes. 23 June 2015: Wouter - Trunk contains 4.1.4 in development. 4 June 2015: Wouter - Tag 4.1.3rc1 - improve nsd-control usage text. (23 june - added to 4.1.3) - RFC7553 RR Type URI support. 2 June 2015: Wouter - Fix redefined macro lex warning for freebsd flex. 29 May 2015: Wouter - Fix that formerrors are ratelimited. 19 May 2015: Wouter - max-interfaces raised to 32. 18 May 2015: Wouter - removed unused defines for unofficial tsig-hmac algorithm codes. The TSIG algorithm is identified by name in the config file. 14 May 2015: Wouter - hmac sha224, sha384 and sha512 support, patch from David Gwynne. 23 April 2015: Wouter - Fix crash in zone parser for relative dname after error in origin. - Test for zone parser failures 21 April 2015: Wouter - nsd-control addzones and delzones read list of zones from stdin. - Fix task and zonestat files to be stored in a subdirectory in tmp to stop privilege elevation. - printout names for successful addition and removal with bulk command. 20 April 2015: Wouter - Fix #665: when removing subdomain, nsd does not reparse parent zone. 14 April 2015: Wouter - trunk contains 4.1.3(upcoming). 7 April 2015: Wouter - Tag 4.1.2rc2. 2 April 2015: Wouter - Made log message more consistent, changed 'axfr refused' log message to be more consistent with other messages. Also notify refused. - verbosity 2 logs axfr refused and notify refused. verbosity 1 contains less log messages. 31 March 2015: Wouter - Tag 4.1.2rc1. 24 March 2015: Wouter - Fix #654: Fix contradiction in notify logging verbosity level. - Incoming notifies have serial number logged (at verbosity 1). - Fix #655: Fix contradiction in verbosity for zone transfers. 17 March 2015: Wouter - Use reallocarray for integer overflow protection, patch submitted by Loganaden Velvindron. - Fix allocation integer overflow checks. 13 March 2015: Wouter - Fix buffer overflow in config parse of domain name, reported by John Van de Meulebrouck Brendgard. 12 March 2015: Wouter - Updated default keylength in nsd-control-setup to 3k. 10 March 2015: Wouter - Fix use after free after zonefile syntax error followed by ttl or origin directive, reported by John Van de Meulebrouck Brendgard. - Fix syntax error followed by too many TXT elements parse crash reported by John Van de Meulebrouck Brendgard. 9 March 2015: Wouter - Fix origin directive from unused old value and subdomain parser failure, reported by John Van de Meulebrouck Brendgard. 2 March 2015: Wouter - Fix b64pton out of bounds error on invalid zonefile input reported by John Van de Meulebrouck Brendgard. 20 February 2015: Wouter - Fix segfault on double origin in zone reader (thanks John Van de Meulebrouck Brendgard). 19 February 2015: Wouter - Remove dead code domain_table_iterate. - Fix segfault in zone reader on invalid input reported by John Van de Meulebrouck Brendgard. 5 February 2015: Wouter - Fix #642: Change 'zone read with no errors' to '.. with success'. Patch from Benedikt Heine. 3 February 2015: Wouter - Tag 4.1.1 release - Trunk is 4.1.2 in development. - Remove some duplicate header includes (from Brad Smith). - Fix tcp waiting list for zone transfers where the bind and connect calls fail. 29 January 2015: Wouter - Fix zonesdir chroot error message. 28 January 2015: Wouter - correct some hyphen-used-as-minus-sign (from Andreas Schulze) in man pages. 27 January 2015: Wouter - Tag 4.1.1rc1 21 January 2015: Wouter - Synthesize CNAMEs with same TTL as DNAME. 12 January 2015: Wouter - Fix casts for ctype functions (from Todd Miller). - nsd-checkconf -f prints out full name of pidfile (with dir). 9 January 2015: Wouter - Fix bug#637: fix that nsd.db grows limitlessly, an off by one on one megabyte free chunks, created during AXFRs of large zones, that caused the one megabyte chunk to be leaked. - Fix udb-inspect for one megabyte chunks, counts and statistics. 6 January 2015: Wouter - Fix spinning NSD with lots of failing transfers, due to pointer comparison using void pointer subtraction (from Otto Moerbeek). 5 January 2015: Wouter - Patch nsd_munin_ from Philip Paeps to use type ABSOLUTE. 4 Nov 2014: Wouter - Document zonestat config, and nsd-checkconf access. 3 Nov 2014: Wouter - Fix that failure to add tcp to tcp base does not leak the socket. 27 Oct 2014: Wouter - Disabled use of SSLv3 in nsd-control. - zonestats are cleared (or not, with stats_noreset). 22 Oct 2014: Wouter - Test for wildcard fix (from 3.2). 16 Oct 2014: Wouter - Fixes for wildcard addition and deletion, speedup for some cases. 15 Oct 2014: Wouter - Fix that queries for noname CH TXT are REFUSED instead of nodata. 14 Oct 2014: Wouter - per zone statistics with --enable-zone-stats, configure with zonestats: "zonestatidentifier", zones with the same id are added. 10 Oct 2014: Wouter - Fix #616: retry xfer for zones with no content after command. - Fix char used as array index warnings on NetBSD. 8 Oct 2014: Wouter - Fix "xfrd_handle_ipc: bad mode" log errors when compiled with --disable-bind8-stats. 18 Sep 2014: Wouter - Fix that expired zones stay expired after a server restart. 15 Sep 2014: Wouter - RFC 7344: CDS and CDNSKEY (read in). 4 Sep 2014: Wouter - Tag 4.1.0. - trunk is 4.1.1 in development. - fix manpage for nsd-checkzone to have version and date. 29 Aug 2014: Wouter - Fix install of the nsd-checkconf man page. 28 Aug 2014: Wouter - Tag 4.1.0rc1 25 Aug 2014: Wouter - Increased default --with-max-ips from 8 to 16, this increases the number of interfaces you can specify in nsd.conf to listen to. 19 Aug 2014: Wouter - Remove .LP after .SH in man pages. 7 Aug 2014: Wouter - Fix for process swap of main and reload, reload failure from the pipe is acted on, and reload fail not cause nsd to shutdown, also ignore sigchlds from the servermain in reload, that would cause EINTR to break file reads. - trunk has version 4.1. 5 Aug 2014: Wouter - Fix #600: document that provide-xfr provides AXFR and not IXFR. - remove program group fix, because it is not needed. - Fix rising-load-average or memory-leaks in OSes (Linux since 2.6), that keep track of all past process parents, or leak memory for them. Fix makes it so there is no very deep string of process parents. The reload process is now the process parent of servermain. That makes signals for children arrive at the reload, and servermain has to use closed pipes to detect that children have exited. 1 Aug 2014: Wouter - Set program group on main process and its child processes, and kill them on a reload. 20 July 2014: Wouter - Fix endian.h include for OpenBSD. 15 July 2014: Wouter - Fix -O3 compile flag to -O2 to avoid miscompilations. - Allow user to override the -g -O2 CFLAGS in ./configure. 11 July 2014: Wouter - fix strptime implicit declaration error on OpenBSD. 9 July 2014: Wouter - removed unnecessary arc4random_uniform. 8 July 2014: Matthijs - fake-rfc2553 patch (thanks Benjamin Baier). 8 July 2014: Wouter - wait and reap processes that are not part of the process group. 7 July 2014: Wouter - Code review fixup from NSD3. 30 Jun 2014: Wouter - Fix #590: rrl log does not print wildcard as a star but escaped. - Fix #591: rrl log messages at verbosity level 1. (If that does not work for everyone, we need rrl-log: yesno option). 27 Jun 2014: Wouter - Fixup rr-test test so that it does not fail on the #553 string. 17 Jun 2014: Matthijs - Fix #587: Default value for statistics is 0. - Remove the shift-reduce conflicts from the bug#553 fix. 5 Jun 2014: Wouter - Fix roundrobin cornercase for truncated packets. - round-robin: yesno in nsd.conf enabled round robin rotation. 28 May 2014: Wouter - Fix #585: yylex_destroy missing, cannot compile on RHEL 5.x. - Fix #583: Round-robin for records in the Answer section. 22 May 2014: Wouter - Fix zonefile parse with no whitespace before semicolon comments. 16 May 2014: Wouter - xfrd reaps children on a timer as well, similar to server_parent. 8 May 2014: Wouter - Fix #564: nsd-checkzone tool to check zonefile correctness. 7 May 2014: Wouter - Fix #577: makefile incorrectly installed manpages from srcdir. 30 April 2014: Wouter - Fix that xfrd reaps all children on every eventloop, because some exited reloads may attach here and need reaping, also if the signal is lost. 23 April 2014: Wouter - Fix progress printout for very large zones (numeric overflow). 10 April 2014: Wouter - Fix write_socket return value check in server.c (Thanks Brad Smith, Mark Kettenis). 8 April 2014: Wouter - nsd-control addzone reports if zone already exists. 7 April 2014: Wouter - Fix #571: unused variable and incompatible pointer warnings when compiled on a system without INET6. 27 March 2014: Wouter - Fix delete or rename of a lot of zones and make it take a non-enormous time. Database compaction is deferred. - Speed up deletion of zone contents a lot, (56s to 1s), speeds up delete, rename and AXFR for zones. Defer emptynonterminal checks. - Better example config in nsd.conf manual page. - log-time-ascii option, default yes, with readable timestamp in log. 25 March 2014: Wouter - nsd shuts down during init process if given signal. - shorter logging for zone transfer fail rcodes. 24 March 2014: Wouter - include: "foo/nsd.d/*.conf" works, wildcard glob on includes. - Fix print filename of encompassing config file on read failure. 21 March 2014: Wouter - Fix bug in nodatabase mode with ixfrs that change nsec3param (Thanks Anand Buddhdev). - Changed maxbackoff for no-content secondary zones from 4h to 24h. - nocontent zones are checked on startup, but continue backoff from stored xfrd.state values. 19 March 2014: Wouter - made database: "" set the 3600 default for zonefileswrite only if it is also at its default, so that user settings override. - Unit test for zonefiles-write. - Write xfrd.state for nodb mode again. Disable xfrd.state with xfrdfile: "" in config. Does not check slave zone if state is same as last time on startup. - Fixed shutdown message sporadically not printed on exit. - Documented zonefile %s syntax in nsd.conf man page. - Fix manpage to put colon after zonefiles check and write. - Change from 'Zone" to "zone" with ".. serial .. is updated" log message. 18 March 2014: Wouter - unit test for nodb mode. - Speed up zone write (.nl zonefile 30% faster). The memory alloc-dealloc in print_rr has been moved to print_rrs. - (from 3.2), fix for #553 and for other TXT string syntax. - in nodb mode, xfrd.state is not written out, because the zones are refreshed upon next startup anyway, so keeping timers and state is unnecessary. - zonefiles-write option in nsd.conf, enabled when database is "". The server writes changed zonefiles to disk every hour. 17 March 2014: Wouter - Speed up zone parsing (.nl reads 40% faster). The rrtype_from_string routine is called often, optimised it. 14 March 2014: Wouter - tag 4.0.3 - trunk has 4.0.4 in development. - database: "" starts without mmap of database. Less memory is used, zones are read from text zonefile. 13 March 2014: Wouter - Fix nsd.db unclean close check. Previous databases are considered unclean by the code and are created anew. - Adds nsd.db larger than 400Tb check for sanity. Also test if filesize as documented in the file is correct. - nsd waits for tasks to complete on stop, prevents nsd.db corruption. - fix to not delete tmpdir too early in shutdown process. 12 March 2014: Wouter - tag 4.0.2 - trunk has 4.0.3 in development. - disabled udb checking functionality that made it very slow, this was enabled when enable-checking was turned on. 27 February 2014: Wouter - tag 4.0.2rc1 26 February 2014: Wouter - Fix that NSD will delete and recreate not-clean-closed databases. 20 February 2014: Wouter - Fix from 3.2: make SOA RDATA comparisons in XFR more lenient (only check serial). 18 February 2014: Wouter - Fix leak of zone name after zonefile read. - Fix malloc too large that would be leaked in the radix tree. 14 February 2014: Wouter - configure change for easier compile on Minix. 10 February 2014: Wouter - Fix #552: zonefile loads on nsd-control reconfig when the name of the file has changed. 7 February 2014: Wouter - Fix #551: change Regent to Copyright holder in the LICENSE, to match the definition on opensource.org for the BSD License. 3 February 2014: Wouter - Disabled recvmmsg and sendmmsg usage by default because kernel versions have implementation issues: ipv6 ignored, security issues. - Detect libevent2 install automatically by configure, and use event2 header files if necessary. - Fixup link with lib/event2 subdir. 30 January 2014: Wouter - Fix expired zones to give SERVFAIL, also when parent zone loaded. 27 January 2014: Wouter - tag 4.0.1. - trunk is 4.0.2 in development. - rcode REFUSED for queries to non-hosted zones. - documented nsd-control zonestatus output in nsd-control manpage. - remove mention of nsdc from nsd-checkconf manpage. 21 January 2014: Wouter - tag 4.0.1rc2 20 January 2014: Wouter - Fix #546: output format errors in nsd_munin_ (Thanks Tom Hendrikx). 17 January 2014: Wouter - Fix type CAA. - Fix type EUI48. - nsid can be set with "ascii_somestring" in ascii. - Fix printout of high-chars in TXT on NetBSD. 16 January 2014: Wouter - Unit test for WKS failure. 15 January 2014: Wouter - tag 4.0.1rc1 13 January 2014: Wouter - Check if configure in srcdir collides with outofdir build. 10 January 2014: Wouter - Fix that chroot is removed from zonefile names (for absolute names). 9 January 2014: Wouter - Fix that bad IXFR updates do not result in double SOA records, and that an AXFR is started (attempted) when the zone state seems to be inconsistent with the master's zone state. 8 January 2014: Matthijs - Bugfix #542: Match RRSIG TTL with SOA TTL in negative response. 7 January 2014: Wouter - Fix xfrd when zone transfer TCP contains zero length packets. - Fix for NSEC3 zones where parent zone is co-hosted, also NSEC3, because AXFRs overwrote nsec3 administration in the child zone. 2 January 2014: Wouter - Log ip address for sendto and sendmmsg failures. 4 December 2013: Matthijs - Support for CAA RRtype (RFC 6844). 26 November 2013: Wouter - Fix segfaults after read of zones with rr type WKS from zonefile. - Seed PRNG for openssl at start of daemon, fixes SSL connection issue. 25 November 2013: Wouter - (same as in 3.2.16): fix wildcard cname to nxdomain repeated rrset. 11 November 2013: Wouter - Fix bug#534: IXFR query loop over UDP for zones that are unchanged. 11 November 2013: Matthijs - EUI48 and EUI64 is now RFC 7043 5 November 2013: Wouter - Accept interface: as an alternative for ip-address: for consistency with unbound.conf syntax. 29 October 2013: Wouter - tag for 4.0.0 release. - trunk has 4.0.1 in development, for bug fixes. 24 October 2013: Wouter - Fixup zone change code. - tag 4.0.0rc3. 21 October 2013: Matthijs - Initialize xfrd zone when changing zone from master to slave and delete xfrd zone when changing zone from slave to master. 14 October 2013: Wouter - tag 4.0.0rc2. 14 October 2013: Matthijs - Additional log messages with reason why RR to be deleted cannot be found. 14 October 2013: Wouter - Fix for zone transfer that has different-cased RRSIG signer names or NSEC next-owner names. 9 October 2013: Wouter - tsig errors on incoming tsig print key name and source IP of query. 8 October 2013: Wouter - Update documentation for nsd -d option. 7 October 2013: Wouter - Fix mini_event ev_once flag to be prettier (review comments Yuri). - tag 4.0.0rc1 recreated. 4 October 2013: Wouter - Fix bug where if you do not have flex, and then install flex, it would not make without a re-untar of the source. 3 October 2013: Wouter - Review changes from Matthijs. - doc/README updated, 'nsdc' is now removed. 1 October 2013: Wouter - Review commits from Matthijs. - doc/UPGRADING updated, review Yuri. 30 September 2013: Wouter - tag 4.0.0rc1 - updated doc/RELNOTES 19 September 2013: Wouter - configure --disable-recvmmsg for compat with older Linux kernels, by default it autodetects support in the kernel on the buildmachine. 20 Aug 2013: Wouter - Fix time at 2038, uint32s changed to time_t, support 64bit time_t. 19 Aug 2013: Wouter - Fix use of 32bit time, for 2038, thanks to Theo de Raadt for patch. 13 Aug 2013: Wouter - Bugfix#518 Incorrect RRL prefix length option names in nsd.conf man page from Ville Mattila. 9 Aug 2013: Wouter - Fix that xfrd, and nsd-control, does not stop responding when reload errors out. The pid is sent like it should by server_main. - Fix that EOF in quoted string error does not cause reload to exit. - Fixup errors from the stack code checker. 6 Aug 2013: Wouter - Removed use of random when arc4random is available. Thus, random and srandom are then not linked with the executable. 16 Jul 2013: Wouter - Fix segfault with no logfile and chroot (Thanks Patrik Lundin). 15 Jul 2013: Wouter - beta 5 tag. - trunk has beta6 named in configure. 9 Jul 2013: Wouter - unlink xfr file if transfer is stopped, timeouted or interrupted. And unlink xfr file in progress when the zone is deleted. 8 Jul 2013: Wouter - Increase tcpbacklog default to 256 (silently capped to 128 on BSD). For remote control keep it at 16, it has less TCP load. It does not actually increase TCP performance (some except), but reduces connection loss when there is a spike in TCP connections. 5 Jul 2013: Wouter - nsd-mem stores temp files in current dir because /tmp is too small. - printout pct parsed, read, nsec3 and written every 100.000 elements and after 5 seconds. For big zones. 3 Jul 2013: Wouter - region-allocator has list of large allocations, so delete is in O(1). - recursive readroutine for speedup of nsd.db reads (30%). - udb-inspect prints type summary of nodes in nsd.db. 28 Jun 2013: Matthijs - Update tmp serial in xfr checking. 28 Jun 2013: Wouter - nsd.db 12% smaller, no nsec3 hash storage. Also ups udb version because of the format change. printout udb write complete for debug. - Fix warning in labellength 0 code. 27 Jun 2013: Matthijs - Better XFR checking, fallback to AXFR (if allowed) if three malformed XFR packets have been seen. - zonec: Don't crash on domain names with label length 0. 25 Jun 2013: Matthijs - Rename --enable-eui-rrtypes to --enable-draft-rrtypes. 25 Jun 2013: Wouter - acx_nlnetlabs.m4 update, --disable-flto. 20 Jun 2013: Matthijs - Use IPV6 minimum MTU settings with TCP to reduce failures that are caused by delays in learning working PMTU when communicating through a tunnel. - Improved RRL logging: also print triggering query src addr and qtype (thanks Klaus Darilion). - Merge some minor stuff from NSD3.2 18 Jun 2013: Matthijs - Add rrl-slip config option (thanks Stephane Bortzmeyer). - Add rrl-ipv{4,6}-prefix-length config option. - Bug #496: Support for EUI48 and EUI64 RR types. 14 Jun 2013: Wouter - Optimizations: -O3 if possible (user can override CFLAGS), udp buffers are set to 1m by default (if socket options exist), use recvmmsg and sendmmsg, or only recvmmsg, or recvfrom. 11 Jun 2013: Wouter - Fix memory leak in zone parser for txt record (since the large number of txt subsections fix). - Fix zone parser allocations to be in db region. - nsd-mem prints advice 5 Jun 2013: Wouter - Fix segfault on repeated reconfigs, double free of zone apex name. 4 Jun 2013: Wouter - Remove duplicate zlfile variable from options structure. 30 May 2013: Wouter - Fix nsd-mem for printout of values above 4G. 16 May 2013: Wouter - Patch from Lukas Wunner that makes chroot more consistent. Make all paths absolute with the chrootdir in front, or use an absolute zonesdir with other patsh relative to that. 3 May 2013: Wouter - Fix race on exit of nsd, for restarts, so that the pidfile-pid process waits until port53 has been closed before exiting. - update acx_nlnetlabs.m4 to v23, sleep w32 fix. 29 April 2013: Wouter - Remove unused pointer and fixup chroot include for trail slash. 26 April 2013: Wouter - Patch from Lukas Wunner that makes nsd.conf include files work inside chroot/etc environments on repattern and reconfig. 25 April 2013: Matthijs - New config option "ip-transparent:", to bind to non local addresses (thanks Arjen Zonneveld). - RRtypes ASFDB, RP, RT should not compress dnames (thanks Peter van Dijk). 19 April 2013: Wouter - own snprintf, fix use of snprintf return value (in debug print). 18 April 2013: Wouter - fix bug #491: pick program name (0th argument) as syslog identity. 9 April 2013: Wouter - Bug #494: Exit with return code 1 if socket code fails. (from 3.2) - Fix B64_NTOP replacement definitions in configure.ac. 26 March 2013: Wouter - update lookup3.c with better endianness detection. 25 March 2013: Wouter - faster nsec3 updates. - Fixup contrib/bug390.patch for 4.0.0b4. - remove leak of nsec3. - allocate radixtree in region for small (5%) total savings and about 15% savings in the radixtree itself (due to many small alloc savings in region). 22 March 2013: Wouter - use less memory for non-nsec3, nsec3tree. 18 March 2013: Wouter - update nsd-mem with pretty printout and RRL count. 14 March 2013: Wouter - Fix memory statistics in nsd_munin_. 8 March 2013: Wouter - nsd-mem tool initial commit. 7 March 2013: Wouter - notify information is logged at correct verbosity level, 1. 5 March 2013: Matthijs - Add hash to rrl bucket 5 March 2013: Wouter - Fixup the growth and shrinkage of nsd.db. This should use less calls to remap and change the file and mmap size. 15 February 2013: Wouter - Fix compile on bigendian netbsd alpha. - Fixup tests for older dig (check if +noedns option is supported) 11 February 2013: Matthijs - Fix outgoing-interface: Don't fail if family is IPv6 but only IPv4 outgoing-interface is set, or vice versa. 11 February 2013: Wouter - fix tcp zonetransfer pipeline lookup function. - remove compiler warning for memset from tsig read. 7 February 2013: Wouter - detect endianness in lookup3 on BSD, patch from Brad Smith. - nsd-control verbosity prints out verbosity level without argument. - nsd-control status prints out ratelimit if ratelimit is enabled. 5 February 2013: Wouter - Fix that old zonefile does not override newer AXFR for slave zones. - Nicer printout of notify. - beta4 4 February 2013: Wouter - Fix AXFR of NSEC3 slave zone. 1 February 2013: Wouter - Less printout of 'bad transfer'. 31 January 2013: Wouter - Fix that nsec3 zones are precompiled when read from udb. This caused assertion failures. - Fix is_apex flag for zones read from udb. 29 January 2013: Matthijs - RRL documented in nsd.conf.sample 29 January 2013: Wouter - printout log less verbosely, not every axfr packet. - remove printout of "bad transfer" to the log for notimpl. - fixup tests for new netstat and new netcat. 25 January 2013: Wouter - fix gcc warning, do not use uninit value for rng init. - fix zonefiles-check: entry in nsd.conf - remove -fwhole-program gcc flag usage. We cannot reliably detect if it works without failure. 23 January 2013: Wouter - beta3 22 January 2013: Wouter - Fix time calculation of zone transfer. - log ip address with tcp failure. 21 January 2013: Wouter - Improve tabs in sample nsd.conf for different tabsizes. - Fix segv if xfrdir does not exit. - create xfrdir on make install (does not remove on make uninstall, because this could be /tmp). - do not leave task files in /tmp if nsd fails to startup because of file permissions. - do-ip4 and do-ip6 nsd.conf options just like unbound. - fixed testset for dig9 default with edns. 18 January 2013: Wouter - Fix configure for gentoo gcc and headers. - List libevent in README. - Tabs and spaces nicer in nsd.conf.sample. - Fix spurious assertion failure for some rrl blocks. 16 January 2013: Wouter - Added zonefiles-check option, default yes, check mtimes of zone files on sighup and startup (from Robin Hack). 15 January 2013: Wouter - documented that the _implicit_ pattern names are used internally. 10 January 2013: Wouter - updated RELNOTES. - applied patch from Robin Hack to remove double pid file truncation. - repattern is called reconfig (because most config options are picked up, except for superuser options (chroot, logfile, port)). - document that the zonefile attribute can be empty. 9 January 2013: Wouter - 4.0.0b2 is beta2 version tag. 8 January 2013: Matthijs - Merge changes from 3.2.15 with trunk: * Update docs: CREDITS, NEW-CFG-OPTION, REQUIREMENTS, RELNOTES, TODO * Update dname_test.tpkg test. * TSIG init only fails if no digests at all can be found. * Remove unused tsig_get_algorithm_by_id code (was used by nsd-xfer). * Fix some fd leaks. * Bug #485: Fallback to DEFAULT_TTL if MSB is set. * Fix RCODE when xNAME loop final answer not exist to NXDOMAIN. 8 January 2013: Wouter - Fix make outside of source directory. 7 January 2013: Wouter - fixed uninit variable for empty zone axfr request - fixed alloc of acl options for config zones so they can be deleted. - fixed that pattern name is copied, so that patterns stay the same. - repattern also rereads the zones in the config file and applies that to the running server. 21 December 2012: Wouter - --with-logfile sets the logfile inside the example documentation. - Fixed addzone and delzone inside chroot (thanks Will Pressly). 19 December 2012: Wouter - Fixup for libevent-2.1.2. 18 December 2012: Wouter - makedist makes sha256 for tarballs. - nsd-control start runs an absolute path to start sbin/nsd. 17 December 2012: Wouter - Fix for use with libev (no use of event.ev_flags). 12 December 2012: Wouter - 4.0.0b1 is beta1 version. 11 December 2012: Matthijs - Better ILNP RR parsing (thanks Stephane Bortzmeyer). 11 December 2012: Wouter - fix libevent=no signals on Solaris. - Fix handle of activated zones from timeout event. - contrib/nsd_munin_ updated with memory lookup for BSD. 10 December 2012: Wouter - implement --with-libevent=no. 10 December 2012: Matthijs - Bug #483: Better error messages for TSIG errors. - RFC 2845: If BADKEY or BADSIG, RCODE should be NOTAUTH. Also, continue TSIG verification if NOTAUTH. 7 December 2012: Wouter - stable pidfile, xfrd is process leader and forks server-parent. 5 December 2012: Wouter - NSD4_imp_6 tag. - trunk has imp_7 implementation. 4 December 2012: Wouter - NSD-RRL documented in manpage. 3 December 2012: Wouter - Fixup exit of server-child while notifies are incoming. 28 November 2012: Wouter - RRL implements classification type RRSIG. 26 November 2012: Wouter - Fix to make nsd.udb portable between 32bit and 64bit machines. - Fix to make udb mmap work for FreeBSD8 when it grows significantly. 23 November 2012: Wouter - Fix compiler warnings and fix blocking pipes. - default tcp-count set to 100. 21 November 2012: Wouter - Implement rrl log of unblock for collision. - imported TLSA and ILNP support from NSD3. 19 November 2012: Wouter - Fix bug 480: libevent use when tcp-count is hit caused hang (in NSD4). 9 November 2012: Wouter - Log when NSD-RRL stops a stream from being blocked. 8 November 2012: Willem - Fix AXFR. Loop through the zone to transfer only. 2 November 2012: Wouter - Fix bug 478: declaration after statement (for gcc 2.95). 1 November 2012: Wouter - Fix default settings for RRL. 30 October 2012: Wouter - review fixup of RRL SLIP response. - RRL uses dev/random at start, nonRRL does not. 26 October 2012: Wouter - nsd-control repattern also changes rrl-ratelimit and whitelist limit. 17 October 2012: Wouter - Fix alignment problem in zone transfer pipeline code. - Fix random generator generating negative. - Fix udb radtree strspace creation bug. 15 October 2012: Wouter - Fix activated zone does not interrupt transfer. - Log of connection failure for zone transfer is neater. 12 October 2012: Wouter - Fix invalid time argument in nsd control (for OpenBSD). 11 October 2012: Wouter - Fix build on OpenBSD (Thanks Oliver Peter). - tpkg for RRL. 10 October 2012: Wouter - implement nsd-checkconf option use of rrl-whitelist. 9 October 2012: Wouter - with --enable-ratelimit you enable ratelimiting, with verbosity 2 it logs what is ratelimited for operational inspection. - unit test for rrl. - rrl uses mmap to save state across reloads. - rrl enum and u16 flags (dnskey type). - rrl whitelist and config. 8 October 2012: Wouter - Sync with unbound lookup3, has raninit value. 5 October 2012: Wouter - fix bug with event loop in zone transfer pipeline. - close xfrd_sock_p in server_child because otherwise due to use of kqueue, it gets a broken pipe when that process exits (on FreeBSD). 4 October 2012: Wouter - Fixup no use of internals ev_flags of libevent. 1 October 2012: Wouter - fix xfrd tcp skip. 21 September 2012: Wouter - tzset before chroot for correct timezone (from Camiel Dobbelaar). - pipeline support for AXFR and IXFR tcp queries. 11 September 2012: Wouter - writev support for TCP. 28 August 2012: Wouter - TXT records with components longer than 255 fail to parse, but without segfault, it continues processing with non NULL value. 27 August 2012: Wouter - libevent in server_child. 21 August 2012: Matthijs - Fix bug#464: Conditionally define MAXHOSTNAMELEN 20 August 2012: Wouter - Fix hang on exit in xfrd. - optimized socket counts for zone transfer speed. 13 August 2012: Wouter - Fix xfrd libevent events. 10 August 2012: Wouter - libevent in xfrd. 26 July 2012: Yuri - Prioritize notify sender for requesting XFR. (thanks Ilya Bakulin) 19 July 2012: Willem - Fix for VU#624931 CVE-2012-2978: NSD denial of service vulnerability from non-standard DNS packet from any host on the internet. http://www.nlnetlabs.nl/downloads/CVE-2012-2978.txt 18 July 2012: Wouter - Fix bug#460: man page correction - identity. 9 July 2012: Wouter - delete temporary transfer files on exit of xfrd and reload. - when tasks are applied, reload checks if it must exit between tasks, so that it can quickly exit when NSD is told to quit. - fix bug in apply_xfr that must use an udb_ptr because it shifts when new allocations are made. 6 July 2012: Wouter - add xfrdir: "/tmp" option and configure --with-xfrdir="/tmp". The nsd.task files and a subdirectory for zone transfers are created there. 2 July 2012: Wouter - fix checkconf unit test and add test for backwards compatibility for difffile: "x" statement. 29 June 2012: Wouter - Implemented /tmp/nsd.xfr.xxx/ to replace ixfr.db. So that nsdc patch is no longer needed. 8 June 2012: Wouter - Fix tpkg test cutest_qroot and rr-test for printout of algorithms as numbers, and copy of DO flag to the answer. - pick up fd fix from 3_2 branch: Some more fd >= 0 to fd != -1 fixes 31 May 2012: Matthijs - Sync with 3.2 branch 24 February 2012: Wouter - Fix for qtype ANY for a wildcard domain in NSEC signed zone. 9 February 2012: Wouter - Update acxnlnetlabs.m4 version 21, fixed MEMCMP_BROKEN #undef line. 23 January 2012: Wouter - remove clang security warning about %n in format string. 20 January 2012: Wouter - Fix bug #430: segfault when MAX_INTERFACES set to more than 65K. - Fix configure for OpenIndiana sunos 5.11, acx_nlnetlabs.m4 update. 12 January 2012: Matthijs - Fix bug #421: truncate pidfile on shutdown, before unlink. 10 January 2012: Wouter - removed unused variables. 10 November 2011: Wouter - acxnlnetlabs.m4 updated to version 16, better lto check (a.out drop). 3 November 2011: Wouter - fflush zonelistfile after zone add or delete. 1 November 2011: Wouter - Fix -flto detection for llvm compiler on Lion. 10 October 2011: Matthijs - Don't clear the AA bit if there is an authoritative CNAME in the answer section (as shown in RFC 1034, Section 6.2.7, 2nd example). 10 October 2011: Wouter - squelch EPIPE when writing AXFR, enable with verbosity 2. 26 September 2011: (Matthijs, from NSD3_2 branch) - Copy the DO bit to the response. - Don't return SERVFAIL on a domain that looks like a NSEC3 domain but is actually a empty non-terminal. 19 August 2011: Wouter - Fix segfault if no logfile is used. 5 August 2011: Wouter - Fix make from repeating action already taken. - Fix compile without openssl. 3 August 2011: Wouter - silence 'Broken pipe' messages in log (visible with verbosity 2). - fix makedist.sh for removal of patch, notify, xfer. new nsd-control. - tag 4.0.0-imp-5 created. - trunk is 4.0.0-imp-6 under development. - added nsd_munin_ script for statistics monitoring to contrib. 2 August 2011: Wouter - fix compile on Ubuntu 11.04 systems, detects cc system header issue. 1 August 2011: Wouter - fix checkconf test for remote control options. - fix warning on Ubuntu 10.04, fix autoconf 2.68 warning on NetBSD. 29 July 2011: Wouter - zones with no zonefile are not written to text (assumes you can get AXFR and IXFR for the contents). They are stored in nsd.db. - test for repattern. 28 July 2011: Wouter - nsd-control repattern reads TSIG and pattern configuration. 25 July 2011: Wouter - fixed tests for removed tools from nsd, with replacements. replaced nsd-patch with nsd-control write. replaced nsd-notify with ldns-notify. replaced nsd-xfer with dig -t axfr. - fix for xfrd restart if crashed. xfrd knows if a reload is active at that time so it cannot start another one at the same time. New shortsoa track for start that does not use taskdb in use by reload. taskdb in use by crashed xfrd is recreated, in case it is corrupt. This keeps the nsd.db intact, keeps reload running with its updated and keeps service from the server processes active. 22 July 2011: Wouter - added contrib/nsd.init (nsdc.sh that only does start,stop). - removed nsdc.sh, nsd-xfer, nsd-notify, nsd-patch. for rc.d: contrib/nsd.init, or platform specific init script. nsd-xfer: see nsd-control transfer, or force_transfer. nsd-notify: see nsd-control notify. nsd-patch: see (cron job to) nsd-control write. 21 July 2011: Wouter - nsd-control notify, transfer and force_transfer. - fix for bug in write and reload zone option. - nsd-control zonestatus command. 20 July 2011: Wouter - reload can be given optional zone argument. - nsd-control reopen_logfile. - nsd-control write changed zonefiles. 18 July 2011: Wouter - Fix xfrd activation of zones to not break running zone transfers. 13 July 2011: Wouter - fix that signal causes stats to be printed to log. - fix stats without remotecontrol. - ignore notify and soainfo for deleted zone, if due to race they arrive after the deletion. - tpkg test for nsd-control, addzone and delzone 5 July 2011: Wouter - fix link to ssl with FreeBSD make. 1 July 2011: Wouter - fix optimize compile to link with ssl. 29 June 2011: Wouter - nsd-control delzone zone. Removes zone from zonelist. - stats includes number of zones. - RAXFR stat, which has not worked since NSD 1.2.4, reinstated. - print more memory statistics, for xfrd and config. 28 June 2011: Wouter - nsd-control addzone zone pattern. Adds new zone, slave or master. 27 June 2011: Wouter - nsd-control stats and stats_noreset (if enabled at compile time). nsd does not print statistics to logfile if period is 0. 23 June 2011: Wouter - -flto check supports clang compiler. 22 June 2011: Wouter - remote control, config, client, setup and status command. - reload nsd-control command. - stop nsd-control command. - verbosity nsd-control command. 14 June 2011: Wouter - Fix to have no authority NS set processing for CNAMEs. 9 June 2011: Wouter - fix bug that relptrs have to be initialized with rel_ptr_init() when created and zeroed with rptr_zero before deletion. - tag 4.0.0-imp4 created - trunk is 4.0.0-imp5 under development. 8 June 2011: Wouter - nsd reads the zonelist file on start. - updated acx_nlnetlabs.m4 to version 11. - configure checks size of off_t and increase region-allocator alignment to 8 if it is 64bit and alignment at 4. - fixed bug where not all references were removed before mmap was synced to another process. 7 June 2011: Wouter - code to add and remove zonelist entries, and unit test. 6 June 2011: Wouter - fix unit tests for mmap with TODO and removal of -f in nsd-patch. - zone expiry is communicated via the mmap, and not via the pipes, simplifying the code significantly as well as making a large number of zones more feasible. 1 June 2011: Wouter - mmap used for parent-xfrd communication of tasks and task results. SIGHUP is sent to xfrd so it can become a task in the normal workflow. This can process about 4500 zones per second (this was with lots of debug prints per zone, in debug compile). The mmaps are file-backed with /tmp/ files. They are removed on a clean exit. - nsd.db and tmp mmaps are created with mode 0600 for safety. - updated flag removed, nsd-patch always in -f force mode (-f removed) and writes all zones always. Its role is taken over by task results. 30 May 2011: Wouter - Fix Makefile for U in environment, since wrong U is more common than deansification necessity. 27 May 2011: Wouter - xfrd is forked before the database is read in, thus it does not consume the memory of the database. It can be reforked on a crash, which is like the current case. Difffile is cleaned by main process and the soa serials are all sent via pipe instead of via forkmem. 24 May 2011: Wouter - implemented patterns in the nsd.conf file. they can be instantiated with include-pattern: x. existing zone definitions keep working (backwards compatible), such zones really have an implicit pattern and cannot_delete flag set. - work on zonelist read and storage. 20 May 2011: Wouter - from NSD_3_2 branch the fix: bug if the zonefile is changed for a secondary but stored transfers are applied, and stop ixfr to empty. The zone is flagged with error, and the good zone is still in nsd.db for NSD4. 17 May 2011: Wouter - unit test for code coverage on nsec3 ixfr. - tag 4.0.0-imp3 created - trunk is 4.0.0-imp4 under development. 13 May 2011: Matthijs - Fix bug #381 - Binary escaped and transfers. 13 May 2011: Wouter - Unit test nsec3 salt change and fix for sanity check of nsec3 chain. pretty prints the nsec3 parameters if verbose. 12 May 2011: Wouter - more unit test for nsec3 precompile changes. - unit test for salt change, rehash in udb fix, remove last NSEC3 from chain works, NSEC3PARAM RR fixed up if RR added or removed from NSEC3PARAM RRset, hashtrees cleared properly, precompile clear more thorough (not dependant on nsec3_conditions). 11 May 2011: Wouter - fixes for nsec3 precompile code: precompile for empty nonterminals created when an RR is added. If SOA removed, precompile stays coherent even though domain_find_zone no longer returns correct zone. 21 April 2011: Wouter - unit test and fixes in nsec3 precompile code. 20 April 2011: Wouter - incremental NSEC3 precompile. 14 April 2011: Wouter - remove chnum. Added numlist sorted by domain.number. domains that are not used are removed. 13 April 2011: Wouter - Fix is_existing flag for ENT when domain that has a shared ENT is deleted by IXFR. - zonec can parse strings with RR in it. - unit test for namedb. 8 April 2011: Wouter - porting complete. - tag 4.0.0-imp2 created - trunk is version 4.0.0-imp3. 7 April 2011: Wouter - ported to sunos 4.1.4, the unit test works (udb, radtree in mmap). 6 April 2011: Wouter - UDB_CHECK is enabled if --enable-checking is used. Because it checks the pointer-administration lists it slows down. - udb-inspect has feature -l that lists zones (and RRs) in nsd.db. - fix memory leak by zonec; the region_cleanup triggers too late. - set listen TCP_BACKLOG to 16 by default, it avoids connect reset by peer in 1000-zones transfer on an ultra10, thus for many-zones. - default xfrd-reload-timeout to 1 second. 5 April 2011: Wouter - Fix uninitialised value in xfrd nsd_soa, the rdata_count. - Unit test for update of the nsd.db with new contents. - Fix array bounds check in radtree-search function. 4 April 2011: Wouter - removed zonec from tests. fix unknown_rr test, enable ipseckey test. increased timeouts on tests that are hard on the filesystem. - Fixed IPSECKEY printout by nsd-patch. 30 March 2011: Wouter - nsd edits nsd.db for IXFR and AXFR messages. since xfrd already checks zone transfers completely for syntax those errors cannot happen, if they do (memory, disk error) the file is left dirty, to be recreated on the next start (and the process dies). 29 March 2011: Wouter - nsd recreates nsd.db if it has not been closed properly or is corrupted (bad header or wrong file format). 28 March 2011: Wouter - NSD without zonec. NSD loads zonefiles on start. NSD stores NSEC3hashes on disk. 25 March 2011: Wouter - Fix bug #365, you can set NSDC_ZONEC_VERBOSE and NSDC_PATCH_STYLE in the environment where nsdc runs. - Fix bug #375, typos in nsd.conf.5. - First step of bug #369: RRSIG DNSKEY sets zone to be treated DNSSEC. - Fix bug #302, nsd accepts XFR but refuses to re-read the slave zone. - NSD4 work: removed zonec, nsdc patch does not write text files for slave zones (as if option is always to binary, this capability returns later), nsdc patch deletes the ixfr.db. kill-HUP rereads zone files that have changed. 24 March 2011: Wouter - compile fixes for BSD. preserve RRset order. 23 March 2011: Wouter - udbzone, store and read zone data in the random-access udb format. 21 March 2011: Wouter - udbradtree works. udb-inspect tool can print radtree details. 16 March 2011: Matthijs - undo fix bug#325: messes up dname compression 14 March 2011: Wouter - udb code added. uses lookup3 from unbound (public domain). - unit test for radix tree in cutest. - unit test for udb in cutest. - udb-inspect tool to printout internals of udb files. for debug, not installed or built by default. - removed --disable-radixtree option. 11 March 2011: Wouter - Removed precompile features, speed gain took too much memory. - domain number to size_t. 9 March 2011: Wouter - DNAME synthesis of CNAME. Uses TTL of the DNAME record. - nsec3 and wildcard code. No additional section for wildcards. Also CNAME and DNAME replies contain only that record (and synth CNAME), the chain is not followed. 8 March 2011: Wouter - precompile work: class ANY gets AA flag, SOA and type-NS processing, just like BIND (9.6) and it simplifies processing for NSD. other than compression difference (precompile compresses smaller), there are no differences in a 49000 query testset against the root, without EDNS. 7 March 2011: Wouter - check chown value and report high verbosity its error. 3 March 2011: Matthijs - fix #bug352: fix hardcoded paths in manpages. 2 March 2011: Matthijs - fix #bug354: make realclean cleans too much - added make devclean for cleaning up autoconf and automake stuff - Fix hardcoded paths in nsd.conf.sample and nsd.conf.5 24 February 2011: Matthijs - fix #bug350: refused notifies should log client ip. 2 March 2011: Wouter - Fix AXFR service with radix tree. - cutest for speed of answer encoding, and format of answers for root. 1 March 2011: Wouter - after merge, remove double -I. from makefile. - radixtree is default. Nicer makefile and no warnings from unused flex functions. 1 March 2011: Wouter - merge with trunk r3181: 24 February 2011: Matthijs - fix #bug350: refused notifies should log client ip. 24 February 2011: Wouter - fix bug#362: outgoing-interface and v4 vs. v6 leads to spurious warning messages. - fix bug#363: nsd-checkconf -v does not print outgoing-interface ok. - fix that nsd-checkconf -o outgoing-interface omits NOKEY. 23 February 2011: Wouter - fix for bug#357, make xfrd quit with many zones. 23 February 2011: Wouter - Merge trunk r3151. 22 February 2011: Matthijs - Patch Jakob Schlyter (setusercontext before chroot). 18 February 2011: Wouter - overhaul of testset, with port uniqueness and fast start and stop. 11 February 2011: Wouter - added test case to do with bug357. 24 January 2011: Matthijs - Patch Tom Hendrikx (only errors to stderr when doing nsdc patch). 17 February 2011: Wouter - Fix leak of compressiontable when the domain table increases in size. - added test case to do with bug357. 10 February 2011: Wouter - Merged with trunk r3115 changes: 20 January 2011: Wouter - Fix on shutdown, then getaddrinfo acquired data uses freeaddrinfo. 19 January 2011: Wouter - Bug #348: no -I/usr and -L/usr for libcrypto in /usr. 5 January 2011: Matthijs - Fix nsdc update and nsdc notify - Force outgoing interface to be a single range acl - Update documentation about acl options - Code review - Fix nsdc so it can use hmac-sha* tsigs - Bug #347: NSEC3 nodata QTYPE=DS not at delegation mismatch 4 January 2011: Yuri - Doc spelling error, bug#345 15 December 2010: Wouter - fix race condition when nsd is stopped while a reload is in progress, often when rc.d does nsdc patch; nsdc stop in sequence. reload is now signalled to stop too. 10 December 2010: Matthijs - fix bug#306: applied documentation patch - fix bug#253: now also for QTYPE=DS. 12 October 2010: Wouter - Fix compilation on SunOS4. 24 September 2010: Matthijs - Bug #328: nsd-checkconf overrun 1 September 2010: Yuri - Support for huge TXT records. 23 Aug 2010: Wouter - fix bug#325: remove stale files from cvs from repo. 16 Aug 2010: Yuri - zonec, MAXRDATALEN check was off by one. 9 Aug 2010: Matthijs - nsdc return 1 outside function, should be exit 1 - Bug #320: arc4random 2 Aug 2010: Matthijs - Bump to 3.2.7. 21 July 2010: Wouter - NUM_RECV_PER_SELECT 100 implemented, configure check if kernel supports this. 17 January 2011: Matthijs - Bump to 3.2.8. 5 January 2011: Matthijs - Fix nsdc update and nsdc notify - Force outgoing interface to be a single range acl - Update documentation about acl options - Code review - Fix nsdc so it can use hmac-sha* tsigs - Bug #347: NSEC3 nodata QTYPE=DS not at delegation mismatch 20 July 2010: Wouter - Branched from trunk. Added radix tree. - use -fwhole-program if gcc supports it. 19 July 2010: Matthijs - fix bug#314, NSEC next field now correctly escapes spaces. Also fixes label overflow issue. - Put back HAVE_SSL. - Code reviews. - Add donor text. 6 July 2010: Wouter - Compiles on Minix 3.1.7; checks ss_family, suseconds_t, some warning fixes. Needs socketpair to work, e.g. http://wiki.minix3.org/en/SummerOfCode2010/UnixDomainSockets. 2 July 2010: Wouter - Put back CHECK_SSL in configure (removed with disable-tsig). 17 June 2010: Matthijs - Expand command line option '-a' and config option 'ip-address:' with port number. - Removed --disable-nsid, --disable-dnssec, --disable-tsig 14 April 2010: Matthijs - Bump to 3.2.6. 14 April 2010: Matthijs - uintptr_t fallback value to void* - Backwards compatibility for MAP_ANONYMOUS - Tag 3.2.5. 31 March 2010: Matthijs - Commit b64_pton optimalized compat code (Martin Svec). - Commit (experimental) mmap-alloc-namedb patch (Martin Svec). - Commit parse-token-leaks patch (Martin Svec). 27 March 2010: Wouter - fix bug#303: misspelled error message. 19 March 2010: Wouter - documented nsid: "hex string" setting in nsd.conf.sample. 24 February 2010: Matthijs - nsid: option - Enable NSID support by default - --with-chroot configure option - Less stupid chroot error handling 15 February 2010: Matthijs - Skip memory cleanup to speed up reload (Martin Svec) 1 February 2010: Wouter - compat code for memcmp unsigned comparisons. 21 January 2010: Wouter - fixup debug sprintf to snprintf. 21 January 2010: Matthijs - Secure string functions, including compat code for strlcat. - Randomness utility function - Prepare for default chroot 6 January 2010: Wouter - check write errors when marking commit failed when difffile is broken. 6 January 2010: Matthijs - Move to 3.2.5 23 December 2009: Matthijs - Store new options in nsd structure. 22 December 2009: Matthijs - New options 'ipv4-edns-size:' and 'ipv6-edns-size'. - Bug 276 - Bug 286 - Bug 288 21 December 2009: Matthijs - New option 'tcp-query-count:'. - New option 'tcp-timeout:' and configure option '--with-tcp-timeout'. - New zone option 'notify-retry:'. 11 December 2009: Wouter - Disable UDP IPv4 DF flag on Linux/FreeBSD/AIX with socket option. 20 November 2009: Matthijs - NSID bugfix: NSD did not recognize NSID in the query. 9 September 2009: Matthijs - DLV support 18 August 2009: Matthijs - Bug 269. - Typo: logincap.h -> login_cap.h 12 August 2009: Matthijs - Maintainers feedback 10 August 2009: Matthijs - Code review. - Also send errors to /dev/null in controlled_stop. - chown nsd.db 7 August 2009: Matthijs - Bug 266: don't have strptime build error 28 July 2009: Matthijs - Bug 263: make TSIG algorithms comparison case insensitive. 23 July 2009: Matthijs - Patch Paul Wouters for NSD using hardcoded name. 13 July 2009: Matthijs - Bug 236: allow RRs before the SOA RR. - Bug 253: No need for NS RRset in authority section, when returning final answer for QTYPE=DNSKEY. 29 June 2009: Wouter - patch for use of Linux IPV6_MTU option, so that on linux the default EDNS UDP size advertised becomes 4096 over IPv6. It fragments the packets using the IPv6 minimum MTU. 19 May 2009: Matthijs - Clean up configure script (install hickup) - Bug 249: Remove unnecessary LLONG_MIN and LLONG_MAX code. - Replace strtoll code with own strtoserial function. - Move up to 3.2.3. 11 May 2009: Matthijs - Add Off-by-one test 6 May 2009: Matthijs - Small fix in SO_REUSEADDR warning log message. - Off-by-one bugfix (thanks Ilja van Sprundel, IOActive) 29 April 2009: Matthijs - A more ensured do_stop (useful fo nsdc restart). 2 February 2009: Matthijs - Bugfix #234. - Bugfix #235. - Reset 'error occurred' after notifying an error occurred at the $TTL or $ORIGIN directive (Otherwise, the whole zone is skipped because the error is reset after reading the SOA). 2 February 2009: Matthijs - Bugfix: return BADVERS when EDNS version > 0, instead of 0x1. 19 January 2009: Matthijs - Bug 230: nsd-*: use stdout for non-error output (instead of stderr). - Don't do strptime test when cross compiling. 17 January 2009: Jelte - Fix file rotation when no logfile but chroot. 8 January 2009: Matthijs - New nsd-patch option -o dbfile (set output.db) - update nsdc to deal with the new nsd-patch options - strptime compat fix 6 January 2009: Matthijs - New nsd-patch option -s (skip writing zonefiles) - Removed some region_create memchecks (not needed) 5 January 2009: Matthijs - Bug 218 - Bug 222 - Replace SHA256_DIGEST_LENGTH with nicer HAVE_EVP_SHA256 10 December 2008: Matthijs - Bugfix: better error message when ixfr.db cannot be read 18 November 2008: Matthijs - chown logfile, don't do file rotation if logfile is outside absolute and outside chroot. 17 November 2008: Matthijs - File rotation for nsd.log when owned by nsd (+ tpkg test). - Only AXFR fallback if master responded NOTIMPL or FORMATERR on IXFR request. - allow-axfr-fallback option. 7 November 2008: Matthijs - Bugfix: don't fclose if logfile == NULL. 30 October 2008: Matthijs - Allow escape characters in literal dnames - Fix typo in zonec manpage - Some fixes from code review 20 October 2008: Matthijs - Redo bugfix literal domain names in rdata (code adjustment) - Added tests for case sensitive dns names and "Bug #162" - Adjust nsd-patch to new ixfr.db format 14 October 2008: Matthijs - Only SO_LINGER when outgoing port is set - Reset diff_skip when a new difffile is created (parts in the difffile now have a timestamp). - Undo bugfix literal domain names in rdata (code adjustment) - Split up dname_parse to parse literal dnames and normalized dnames. 3 October 2008: Matthijs - setsockopt SO_LINGER, for portability outgoing-interface (BSD/Solaris) 1 October 2008: Matthijs - Configure the source ip-address for notifies by the master and zone transfer requests by the slave in nsd.conf. - Previously added source hostname/ip and port configuration for nsd-notify and nsd-xfer - Finetuned nsdc for nsdc notify and nsdc update 29 September 2008: Matthijs - Bugfix: only normalize domain names in rdatas when rrtype is listed in RFC 4034, section 6.2: Canonical RR Form. - Update TODO list 25 September 2008: Matthijs - Fix bug where hmac-sha256 was in algorithm table, but could not be retrieved by name or id. - Additional arguments for nsd-notify and nsd-xfer: set outgoing hostname/ip-address and source port. - Additional TODO entry: optimize code in nsd-* programs. 8 September 2008: Matthijs - RFC 4635, bugfix #130: support for hmac-sha1 and hmac-sha256 tsig algorithms. - modify and add tpkg tests for hmac-sha1 algorithms. 2 September 2008: Matthijs - AXFR fallback when IXFR/UDP failed on all masters - Bugfix: strip off chroot value in corner cases - Additional debug and verbose log messages 29 August 2008: Matthijs - IXFR allow UDP option 26 August 2008: Matthijs - Code layout, additional comments and documentation typo fixes - IXFR over TCP, no longer UDP 17 July 2008: Matthijs - Make the maximum number of interfaces configurable. - Write pidfile *after* successful server initialization, instead of writing, and unlink if fail. 16 July 2008: Matthijs - Set upcoming release to 3.1.1 - Wouter: fixed memory leaks that happened on error, mostly on zone transfer errors. 11 July 2008: Matthijs - Avoid race condition in nsdc: let nsd server update pidfile before closing old parent process. 8 July 2008: Jelte - Fixed NSEC3 memory leak in the case NSEC3 is not needed. 7 July 2008: Matthijs - Bugfix #191 9 June 2008: Matthijs - When comparing RRs, do not compare TTL values (since the same record with different TTL values are considered equal). - Fixup some more unaligned memory access that could occur when reading ixfr.db. 19 May 2008: Matthijs - Do not always log tcp read errors, only when real error or high verbosity 28 April 2008: Matthijs - Bugfix #172 (misleading error from zonec) 27 March 2008: Matthijs - Port some branch modifications to trunk 28 February 2008: Matthijs - Do not answer nsec3 wildcard information when DO bit is not set 19 February 2008: Matthijs - Fixed strptime bug (for MacOS Leopard) 22 January 2008: Matthijs - Add configuration for chkconfig to control nsd service (bug 164) 15 January 2008: Matthijs - Fixed bug 157 where nsd would return FORMERR if edns query is received with version set to zero and rdlen is larger than zero. 8 January 2008: Wouter - no warning about optout records. also no warning about missing nsec3 records. - check for hash(apex)==nsec3 with SOA bit was done in duplicate. - removed old commented out code - using SOA bit in NSEC3 typemap to detect parameters - using nonhashed NSEC3 to prove qtype=NSEC3 nxdomains - prints for debugging. - nicer comment on nsec3_lookup. 7 January 2008: Wouter - Fixup nsec3 tests, they need zonesdir: "." in conf files. The tests pass. - configure default is --enable-nsec3. Disabling this will save 20% more memory (for very large zones). Moved tests to test on commit. - set RRTYPE numbers for NSEC3=50, NSEC3PARAM=51. - fixup checkconf test - updated parser lexer gives syntax error on some garbage instead of parse error. Parselexer is updated for new options (hide-version, verbosity). - removed highrange rrtype code. fixup cutest for that. - speedup of prehash code. - skip nonexistent domains (operator.example.com). - skip only-nsec3 domains (that could be 2x speedup) - skip glue nameserver domains (for TLD with 2 glue per delegation this is a 3x speedup). - skip the prehash_domain for delegation points, which saves another 2/3 hash operations, 3x speedup. - printout how long nsec3 prepare took (verbosity >= 1). 3 December 2007: Matthijs - Fixup bug where data related files are looked up in the wrong directory when chrooted with chrootdir ending with a slash. 26 November 2007: Matthijs - Fixup bug start nsd while already running: do not initialize server, since it is already running. 15 November 2007: Matthijs - Changed man pages format from mdoc to mansun, to support the Solaris OS. - Better logging for nsd-notify (show 'broken' zone) 13 November 2007: Wouter - CREDITS and RELNOTES now in utf-8. 12 November 2007: Matthijs - Changed man pages according to bug 162. 30 October 2007: Wouter - Fixup for skip after unknown deleted IXFR RR, otherwise processing would continue at the wrong spot in the packet and process the IXFR as if it were malformed. - added unit test for this in long (needs ldns-testns, updated it). - added unit test for rollback of malformed zone transfers. Fixup for it, and fixup in ldns-testns to be randomport and copy id for hex packets. 29 October 2007: Wouter - Fixup bug where malformed IXFR replies cause partial processing in reload (or nsd-patch or nsd-startup). One result is multiple SOA records in zone apex. Fixup rolls back the zone transfer, and waits for NSD to try to load again. 26 October 2008: Wouter - small fix in descriptive text in sample config for debug-mode. 9 October 2007: Mark - Change default location of: nsd.db, ixfr.db & xfrd.state to /var/db/nsd. 5 October 2007: Wouter - Fixup manual page entry for allow AXFR to anyone. 3 August 2007: Mark - Report source and zone for denied AXFR attempts. 25 July 2007: Wouter - bind2nsd to 0.5.0, fixup of includes, key{} handling. 19 July 2007: Wouter - bind2nsd to 0.4.8, fixup of include bug. 18 July 2007: Wouter - added contrib for bind2nsd, Al Stone provided an abridged version that neatly fits for contrib. 17 July 2007: Wouter - fixup commithooks. 16 July 2007: Wouter - Added reference to http://bind2nsd.sourceforge.net/ to contrib/README. 3 July 2007: Mark - Zone compiler now gives more sane error message when out of diskspace. - Fixed a call to drill in tpkg that made a test check bind instead of nsd. 2 July 2007: Mark - Remove last traces of mmap usage. - Some cleanups in tpkg. 24 April 2007: Mark - Added "hide-version" configuration setting. Enabling this feature stops NSD from answering to CHAOS class version requests. 19 April 2007: Wouter - Compiled on minix 3.1.3 and make some adjustments to ease porting. ECONNABORTED is checked for. sys/select.h included in nsd-notify. SO_REUSEADDR failure is not fatal. PF_INET compat code added. If you compile yourself; strptime and socketpair need compat code. 13 April 2007: Wouter - Minor tweak to nsec3.c, more elegant handling of malformed nsec3 records from a zone transfer. 10 April 2007: Wouter - Fixup ignored return value in region-allocator. Now returns a NULL memory allocation failure and leaves region in a consistent state. 20 March 2007: Wouter - Released 3.0.5. - (for 3.0.6) -O2 test for Alpha moved to saner position. 16 March 2007: Wouter - port configure to AIX, removed warning on ALIGNMENT in region code. defined _ALL_SOURCE to get recent C definitions on AIX. - improved nsec3.h comments. 22 February 2007: Wouter - Zonesdir default is now /etc/nsd. So that the invocation directory is not used to dump files into. The user can change the zonesdir by editing the config file. The directory is created by install, if not an error is printed. - updated tpkg tests to use current dir for testing. - tcp connections that drop do not spam the log file. Unless verbosity is set high. 19 February 2007: Wouter - Fix empty line printed with warning on 'force zone transfer'. 15 February 2007: Wouter - Check for EPROTO definition to compile on FreeBSD4/Alpha. 13 February 2007: Mark - Debug flag (-d) behavior changed. Nsd now also forks children when run in debug mode. - Added verbosity mode (-V ) for extra operational logging. 8 January 2007: Wouter - README text on interface configuration added. 2 January 2007: Wouter - Fixup accept() that could block due to already closed connection. Made listen() nonblocking, ignores errcodes that indicate closed tcp. 29 January 2007: Mark - Handle the new CERT RDATA types defined in RFC 4398 (submitted by Mans Nilsson). - Change nsd-notify retry timer from linear into exponential backoff (submitted by Mans Nilsson). - Due to a small bug in a comparison statement, zonec would fail on the parsing of unknown CERT types. This got triggered by the first bugfix today, as that one shouldn't have been discovered in the first place. Took the opportunity to sanitize two other comparison statements related to strtol(). 24 January 2007: Wouter - Tentative change to set UDP sockets nonblocking. Perhaps it helps Howard. 19 January 2007: Wouter - NSEC3 work. prehash printed only once with time taken to prepare. - prints are now only in DEBUG mode (except errors). - rr descriptor counts for NSEC3 updated, has an extra field flags. - now NSEC3PARAMs with flags!=0 are ignored, as per draft-09. - Fixed where only first NSEC3PARAM was properly detected. - Added tpkg in manual (because you need to compile with nsec3) that performs the test queries from draft-09 and checks them. - Made tpkg to test NSEC3 parameter detection. NSD will skip any NSEC3PARAMs that don't work until the first working one is found. Also, this means unknown hash algorithms are simply ignored. A zone that uses exclusively unknown hash algorithms for NSEC3 will give errors on loading (or after zone transfer) but NSD will load and serve the zone (but no NSEC3s are returned). - added tpkg in manual to test parent side DS answers. These follow a different code path than child side DS. - Will allow NSEC3s(and signatures) below a DNAME. - A query for an NSEC3 ownername will lead to DNAME redirection as if the NSEC3 did not exist. - Test package in manual that tests NSEC3 and DNAME in the apex. - Changed NSEC3 memory requirements from 5 pointers per domain name to 3 pointers and 2 bits. - Added jumpstart for nsec3 search, will greatly speed up optout zone nxdomains. At the cost of one ptr per domain name. The speedup also speeds up the nsec3 prepare stage. 18 January 2007: Wouter - Created 3.0.4 release tag. - 3.0.5 number in trunk. - add nsd.spec patch from Farkas Levente to contrib. - NSEC3 new wireformat and presentation format from draft-09. 11 January 2007: Wouter - The message 'server .. closed cmd channel' is now priority INFO. This to reduce the 'error' amount in the logs. - On error in a tcp request, set to retry next instead of waiting for the tcp timeout. 9 January 2007: Wouter - TSIG acl matching changed so that NOKEY allow-notify entries match only queries without a tsig. Otherwise NSD would crash. This only affects servers that have allow-notify: ip NOKEY and someone sends a TSIG signed notify from that ip. - test package for that. - Fix for reply to notify messages with ANCOUNT wrong. The ack to notify messages that passed the ACL, and had a SOA in the answer section of the query, included wrong RR counts in the header. - test package for notify reply wireformat. 8 January 2007: Wouter - ipc_send_blocked will not lead to busy waiting on it, but will block in select, until SOA_END comes by. - server_main sends SOA_END if reload crashes, to xfrd. So that xfrd can set ipc_blocked=0 and can_send_reload=1; and thus resume service, assuming that the crash was a temporary condition. This will lead to trying every reload-timeout seconds to reload if it is a permanent condition. Which is more obvious to the operator. - put the error "error: diff: RR ns.kiev.ua. already exists" in debug mode only. Zone transfers with this error are liberally accepted, and we should not spam the logfile. - empty zones will not be retried forever every 10 seconds, but exponential backoff to a max of every 4 hours. The exact value is randomised to spread out attempts. 5 January 2007: Wouter - Fixed --zonesdir= for configure. The value did not get used as a default value. Now it is used as a default value. If a default value is set for zonesdir, you can go to a 'no value specified' by giving the empty string, zonesdir: "" in nsd.config. - Fixed checkconf.tpkg for this change. nsd-checkconf will output zonesdir: "" as this is the default for --zonesdir. 2 January 2007: Wouter - Added contrib script from Stephane Bortzmeyer to convert NSD 2 to NSD 3 config files. Converts secondary zones and TSIG keys. - Made config conversion script skip empty lines. - Made config conversion script convert primary zones (and notify). - Nsdc control script will exit with 'nsd startup failed.' if nsd fails to start (due to bad config file for example). 15 December 2006: Wouter - Removed dlopen() checks from configure.ac, NSD3 no longer has dynamic plugin support (since 3.0.0). - added .rpm spec file to contrib. - Updated README to remove reference to buildzones script. 12 December 2006: Wouter - Added missing include to ipc.c to compile on SunOS. - Cast to avoid signed/unsigned comparison in compat/inet_ntop.c. 11 December 2006: Wouter - Added test to check for CNAME and other data error by zonec. Currently NSEC, NSEC3, RRSIG, SIG, NXT are allowed next to CNAME. - Fixup unaligned memory access that could occur when reading ixfr.db with a partial transfer inside. - RR type WKS (well known service) was not printed correctly, htons() was forgotten when calling getservbyport. - NSD does not complain about not being able to read the db CRC when all that happens is the file became longer or shorter. 8 December 2006: Wouter - Moved down max XFRD UDP sockets for zone transfer queries to 100 down from 300. This makes the total socket max at 200, so it fits easily under 256 ulimit (a common default). 7 December 2006: Wouter - Improved error message to help operator. - created 3.0.3 svn tag. - default of zonesdir corrected (no directory is default). 4 December 2006: Wouter - updated test packages. Moved 213_large from manual to long. size_0, source_port_0 made more working (needs root permission). 1 December 2006: Wouter - Moved xfrd ipc and reload handlers to front of event handler lists for a 10% speedup in xfrd. - Fixed so that NSD no longer interrupts zone transfers when a notify comes in for that zone. Added package to test it. - Fixed warning on Solaris 10. 30 November 2006: Wouter - Test for fallback in getaddrinfo more portable. Ported to FreeBSD 6.1 without inet6. - New quit sync had a problem with blocking in dispatch. Fixed. - reload will retry quit_sync if nothing happens. - parent tries to empty the pipes before closing them on quitsync. - xfrd does not send reload when previous reload request busy. - netio will only deliver the number of bits from select and then stop. Optimisation. 29 November 2006: Wouter - Fixed getaddrinfo error message to be more descriptive. - Fallback to ip4 also if getaddrinfo fails for ip6. - instead of EAI_ADDRFAMILY uses EAI_FAMILY which is portable to FreeBSD. - signed/unsigned warning fix for FD_SETSIZE comparison. - Lots of debug statements and new quit sync feature, where the server children are synced with. So as not to lose buffers. 28 November 2006: Wouter - Debugging 10k zones transfer, set so that zones waiting for a socket do not get timeouts. - Debug change so that an event is only returned to one handler by netio. Reversed this. Netio will not deliver events you do not listen to, and since xfrd first listens to write then read, it will not have problems with stale events (for the fd from the previous select) because these are always read, while it needs a write. Re-Reversed it: netio will deliver events only once. This is easier to understand for the poor hapless developer. - Need to set notify_current for notify on waiting list. Fixed. 27 November 2006: Wouter - Debugging 10k zones transfer, noticed that it is possible for netio to give a callback for an event that you were not listening to. Now no longer does that. 16 November 2006: Wouter - Bug #153: now checks for FD_SETSIZE when adding fd to select fdset. - Easy overview of socket allocation for xfrd in xfrd.h - Upped the default xfrd socket limits a bit. - Log message that the TCP connection limit is reach is now only in -L 2 logging. It is spammy. - updated dependencies. - Added test for notify-socketcount, and removed unused files from bug153 test package. - Notify udp sockets are also capped at a max number. The rest has to wait in a queue. 15 November 2006: Wouter - Fixed bug #152: identity keyword in nsd.conf did not work. What happened was that the hostname() from the computer was overriding the nsd.conf identity. Fixed now. If commandline is given that is used. Else nsd.conf entry is used. Else hostname() detected from computer is used. Else default string "unidentified" is used. 14 November 2006: Wouter - Fixed bug where NSD tries to create 10000 udp sockets, when starting with 10000 secondary zones. Limited to 50 at a time. The XFRD_MAX_UDP constant controls this. 3 November 2006: Wouter - Created tags/NSD_3_0_2_REL. 2 November 2006: Wouter - Added pdf for differences.tex for ease of use. - Updated text in readme on memory usage. 24 October 2006: Wouter - Recycle rrset memory after doing special processing on the deleted rrset data. - log message clearer for 'duplicate xfr part' to 'discarding partial xfr part'. - if you have a server that has IXFR turned off but sends a TC flag for IXFR queries, xfrd will retry to TCP. This makes the use of 'AXFR' flag in nsd.conf file not needed in certain cases. - Be thrifty and save up the memory that was lost at end of chunks in the recycle bin. Saved 1.3Mb on 170(rrs)/220(total) Mb dataset. 23 October 2006: Wouter - Added checks for out of memory in reload (diff file). And it exits if so neatly. 13 October 2006: Wouter - Bug #149: Wrong text for NOTAUTH error code. When notify is not authorised REFUSED error code returned instead. 4 October 2006: Wouter - More fixes from Koh-ichi Ito (kohi@iri.co.jp now), for bug #146, his bash does not do $(( )), so nsdc.sh has to use test of course. 29 September 2006: Wouter - recyclebin works, added a test that uses it (about 3 Mb goes through the recyclebin). This resolves bug #147. - Made -L 1 logging is little less verbose (-L 2 gets it all). - added search path for openssl on Solaris 10 (/usr/sfw). 28 September 2006: Wouter - Removed unused global variable current_region, and routines for it in region-allocator.c and .h. - Added recycle option to regions. It will keep track of small objects in a recycle bin. Large objects are deallocated. No calls to recycle yet, unit test it first. - added unit test for region recycle. 27 September 2006: Wouter - Further suggestion from Koh-ichi Ito, I've set opt->xfrdfile to XFRDFILE in options_create. So opt->xfrdfile and opt->difffile are never NULL. This simplifies code elsewhere. And also handles chroot case (+=l) for default values. - Fix for bug #145. The skip file position in the diff file was used inconsistently - one part of the code skipped to before the 'IXFR' type code and another part skipped to after that. Now all skip to before the type code. This bug only happens if your diff file is like: zone1_part1, zone2_part_1, zone1_part2, zone1_commit, zone2_part2, zone2_commit. The skip over zone1_part1 failed. - tpkg test in long dir that tests for the bugfix. Takes a long time and uses ldns-testns feature to wait partway through an AXFR. - removed debug log of strerror on diff read failure, when the errno was already output to the logfile (resulting in a nonsense error). 26 September 2006: Wouter - NSD compiles on Solaris 10 with the sun cc compiler. Added a define for _STDC_C99 for that. - Checked that the patch for solaris for bug 143 indeed fixes the bug. - Fixed bug #146 reported by Koh-ichi Ito: when chrooted nsd failed to write xfrdfile/difffile. 18 September 2006: Wouter - no queries for NSEC3, RRSIG, ANY succeed for nsec3 only domains. 15 September 2006: Wouter - Fixed LOC parsing of integer overflow causing maximum values. Added to test and backported fix to 2.3.6. - NSEC3 qtype queries get noerror/nodata or nxdomain answers. You can query for NSEC3PARAM. - warnings for printf format on maxOS (sizet needs cast to int). 13 September 2006: Wouter - added fsync to AF_UNIX sockets to write last command (QUIT) before closing them. - sent explicit QUIT command to xfrd on final shutdown of the server. 12 September 2006: Wouter - Bug #144: LOC defaults for unspecified values wrong. Error in zonec. Set defaults. Also fixed parser if LOC has no minutes or seconds. - Also fixed rounding error in seconds 0.001 decimal. - Test tpkg for bug 144. 11 September 2006: Wouter - nsdc now more portable in use of 'which'. Does not only look at exit code but also checks for '^no ' string. - nsd-patch does a chdir to zonesdir for relative difffile or dbfile path names. - nsdc handles zonesdir: for relative pidfile, dbfile, difffile pathnames. 7 September 2006: Wouter - bumped version to 3.0.2. - Nice configuration error when you had the wrong zone name in the nsd.conf file. Zonec will give an error already. - When you start a secondary zone without a zone file, you get a much nicer error message, warning you of the zone transfer. - Credits for prerelease testers; Thanks guys! 6 September 2006: Wouter - Fixed nsd-patch so that it writes the SOA at the start of the file. - test tpkg that tests for the bug, has multiple rrsets at zone apex and does nsd-patch followed by zonec. Previous tests did not catch this: they used nsd-xfer to test zone contents, or only checked the zone-file after nsd-patch. - version number bumped to 3.0.1. - svn tag 3_0_1 made. 5 September 2006: Wouter - differences file improvements. - created 3.0.0 release in svn tags. 4 September 2006: Wouter - From suggestions by Bin Zhang: - nsdc restart does not fail if nsd was not running. - fixes to man pages, wrong locations for files. - NSEC3-PARAM has no optout bit in presentation format. - NSEC3PARAM spelling. - differences in latex format (needs nlnetlabs housestyle). 31 August 2006: Wouter - Fix for tsig size still set when data is null ptr. - Fix configure for NetBSD (1.6 - 2.0) to find struct timespec. - DIFFERENCES file completion. 30 August 2006: Wouter - Print error nicely when nonblocking connect fails on systems in a portable way. - doc/UPGRADING document to assist NSD 2 to 3 upgrades. - updates of error print - ignore EINPROGRESS if we check too early. - wait for select writable before testing for connect error. - echo "" >&2 is not as portable as we would like, removed from nsdc. - fixed debug print of a null ptr. - fixed bug where query for CNAME that points to unserved zone caused nullptr exception on empty zone ptr. Now original zone is restored after CNAME-pointed data is added to the packet. Test in dname.tpkg. Reported by Kai. - fixed stack corruption when ipv6 disabled. 29 August 2006: Wouter - NSEC3 made it so it can handle the case where the NSEC3 RRSET with the SOA bit on does not have the RR with the soa bit set as the first RR. - Handle NSEC3-PARAM type. Checks to see if any of them work: zone apex hashed exists, with NSEC3 type, and RR that has the same parameters and the SOA bit set. - in presentation format of NSEC3, NSEC3-PARAM reversed hash, optout. - update to the DIFFERENCES file, bind 9.3.2 vs NSD 3 and NSD 2 and 3 comparisons are completed. 28 August 2006: Wouter - echo messages in nsdc made clearer. nsdc notify and nsdc update only send notify messages to slaves / localhost to force transfers. - initial NSEC3-PARAM type code entry. parsed, ignored. 25 August 2006: Wouter - disabled make test target as tests are not shipped. - performed prerelease static snapshot. - updates to the DIFFERENCES document. 24 August 2006: Wouter - Fix bug 141 port from 2.3.6, copies behaviour from bind 9.3.2. - Added a test for bug 141. - Bug141: save the opcode from the query. 23 August 2006: Wouter - Fixed % by 0 exception in the bugfix #139. - Fixed RFC 4035 says CD flag SHOULD be cleared on authoritative responses, now NSD clears the CD flag. This is bug #140. RFC 4035 could be confusing on this, as it states 'all servers MUST copy the CD bit' more than once, but then makes clear only recursive servers are meant with that statement. - Differences document updates for bind 9.3.2 and nsd 3. 22 August 2006: Wouter - version number to 3.0.0 in preparation for release. - Bug #139: resync stats to whole period. Fixed. 21 August 2006: Wouter - check for error in ftruncate call. - replaced fwrite call with write_data call from util that does error checking. 15 August 2006: Wouter - removed unused struct nsd.named8_stats variable. - Bug #138: nsd aborts trying to bind all interfaces if ip6 is not enabled, instead it will fallback to ip4. 14 August 2006: Wouter - Added test for rollback of an IXFR transfer by xfrd. - Added test for reload timeout in xfrd, the reload does happen after a while, but not immediately. - Test that makes xfrd connect to ip6 address. - Test that overloads the number of tcp connections in xfrd, simulating a slow master, so that zones have to queue up to get it. - code coverage is now 2514 of 10636 uncovered. Still a lot uncovered. - ixfr queries return NOT_IMPL errors. 11 August 2006: Wouter - srandom to init random() in xfrd based on PID and time. - improved usage() information to be more helpful, and with version. - in makedist.sh, flex and bison called like in Makefile. - test for tcp underrun and overrun of the buffer. 10 August 2006: Wouter - added more tests to increase code coverage of testset. - moved acl parsing code from configparser.c to options.c to help unit testing. - nsd-checkconf echod wrong difffile filename with -v. - nsd-patch can now be used with -f to force printing of all RRs. - TYPE_NULL crashed NSD when it printed it, arg was ZF_DNAME, now ZF_UNKNOWN. - unknown rr test was faulty on input, the length was in nibbles not in octets, but rfc specifies octets for unknown rrs. NSD does not look at the length, and prints the length correctly. - added type NXT to the rr-test for weird RRs. - added printing test to rr-test, ipseckey and unknown-rr tests. checks if NSD prints the same RR on output as it read in. - put -x option for nsd-patch in usage(). - test that kills an nsd child server and checks that it is restarted. 9 August 2006: Wouter - tested nsdc functionality, make install and make uninstall. - set O_NONBLOCKING on xfrd tcp sockets before the connect call, because the handshaking can take very long too. - difffile and xfrdfile set via configure, to absolute pathnames, so that chroot checks work for them. - updated tpkgs, they need to set relative paths now for difffile. - gcov says 2821 of 10617 total code lines are not covered. compiled with --coverage, not -O2, ran tpkg/* and long/testplan*. counted grep '#####:' *.gcov | wc and grep '^ *[0-9]*:' *.gcov | wc. - cleaned up the log functions, NSD no longer spams the syslog with debug messages. The standard NSD debug util is used, -F -1 -L 2 for a compile configured with --enable-checking will enable them again. Errors are logged, as is the automated reload of a new serial. - tpkgs for bug077 and bug107 were silently failing to test properly. 8 August 2006: Wouter - fixes for checkconf test, more portable. - removed items from TODO that have been tested. for multihomed servers you have to bind to each interface explicitly to get outgoing ip-address the same as query destination ip-address. Forks and if-existing are tested and ok in testplan tests. close_all_sockets is called by child, if tcponly, so leave it. - user name check is hard portably with shell scripts, and packaging could set a default user that does not exist on a machine. - empty nodes (nonterminals) give no nxdomain any more (todo item done). - removed (old) from TODO. - removed contrib/buildzones.pl, it is outdated. 7 August 2006: Wouter - Made the tests a little more portable. - fixed mempcy unable to handle unaligned memory addresses on Solaris, used memmove instead of memcpy in zonec LOC conversion code. - another unaligned memory access, when storing off_t pointer in difffile.c, used memmove. 4 August 2006: Wouter - nsd will start if diff file is corrupt, with a log message. It ignores the bad data. - tpkg files do not override PATH, svnhook sets it. So user can set path to utilities on the system to run the tests. - running testset on DecAlpha discovered uninitialised variable in NSD. Fixed. - Jakob Schlyter asked for building nsd3 in an obj dir, i.e. mkdir obj; cd obj; ../configure && make. Fixed up makefile for that. - and bug137.tpkg for separate obj dir building. 3 August 2006: Wouter - more tests in mesh test. - changed test packages to put nsd log to test result "/dev/stdout". - test packages more portable - use default 'dig' location. also, path is appended to, instead of replaced. 2 August 2006: Wouter - Region can be customised for detailed memory handling. Especially if you set large_object_size=0, chunk_size=0, the region will perform individual allocs, and 'save memory'. The region still keeps tracks of allocations so that at region_free time all memory is released. - tsig.region removed, it was not used after attaching a cleanup at creation. tsig creation uses custom region settings. - xfrd inits the tsig records with memory saving settings, so the regions alloced for tsig take up about 60 + 4*8 bytes. - new custom region for query region - to make chunksize larger there. The chunksize for the query region is important, if all allocations for a query fit in it, no mallocs are needed. - TSIG other_data field size according to RFC 2845 is 0 or 6. In tsig implementation put a maximum to the field of 16, otherwise a formerror results. - query with IXFR appended SOA not formerror. IXFR queries not reach the handler in axfr.c for IXFR queries. - removed annoying debug message of added tsig key. - added test that starts 7 servers in a mesh and lets them fight out what zones to transfer and serve. - xfrd logic bug: if notified a slave would not see the renewal of its current zone. 1 August 2006: Wouter - Test for remove domains with IXFR. - Fix for empty nonterminals and IXFR deletes. - Test for timeouts, including expiry, and expiry and zone updates. - Test for axfr refused authorisation. - Test for deadlock in ipc. 31 July 2006: Wouter - Test plan ixfr test in tpkg/long directory. - IXFR with many packets tested (one RR per packet). 28 July 2006: Wouter - tentative change, that preserves ordering of rrtypes for a domain. - fix for serial rollover (old_serial + 2**31), now works, is seen as new serial and rolled over to new. - serial numbers, and time values, printed as unsigned to logfile. - set so that if info is provided by operator, refreshing state not expired is used. - forgot to * a pointer to boolean, is_ixfr in the difffile reader. This fixes the testplan_ixfr test 1. 27 July 2006: Wouter - fixup desc of tsig xfer test, remove debug from xfr_huge. - fixed compressed dname tables cleanup, to set ptr to NULL. - initialised xfrd_listener.fd to -1. - fixed difffile handling of very short AXFRs, with no data. 26 July 2006: Wouter - Updated the requirements with comments from Olaf. - README discourages use of experimental nsec3 rr a bit more. - typo in DNAME code, used original qname instead of CNAME adapted qname variable. - added IPSECKEY RR type, RFC 4025. - tpkg test with sample ipseckey rrs. - wireformat for IPSECKEY depends on the value of a rdata atom, added WF_IPSECGATEWAY to handle that. - DHCID type, data is encoded in one binary/b64 blob. 25 July 2006: Wouter - max number of tries for nsd-notify is 15, so that the total time for sending is about 75 seconds. - forward port of fixes for bug 105 and 135 in nsdc. forward port of test for bug 105. - fixed nasty bug with configure --prefix=<...> where config.h was wrong. Now double evaluate the shell expansion on the defines. 5 July 2006: Wouter - helped in README with gnu make; need to make clean so that botched attempts by make to create the lexer files do not stay around. - removed %zd, replaced by casts to int. - updated REQUIREMENTS file, the sections on RR types, on what algorithm NSD follows and on which RFCs are supported are updated. 3 July 2006: Wouter - 'make depend' target in makefile. (updates both Makefile.in and Makefile, so it works for users and for svn). - doc minor update. 2 July 2006: Wouter - TESTPLAN, README, bugzilla-bugs docs updated. - NSD for BIND users update. 29 June 2006: Wouter - removed --zonesfile nsd.zones configure option. - doc/README updated for 3.0. - doc update. NSD_FOR_BIND_USERS document. - moved from -Ds to the config.h header, cleaner compilation output. - use autoconfs built in large file support enabler. 28 June 2006: Wouter - nsdc neater, checks for BLOCKED ips more strictly. - nsd -d also disables xfrd forking, and thus all reloads and secondary zone treatment. Stated so in manual page. - fixup, apart from ip4 need to allow ip6 in example.conf line showing how to allow access for everyone to axfr. 27 June 2006: Wouter - Fixed read in server.c to be a blocking read for sure, even if ipc is not blocking on the OS. - nsd-notify tries to send notify 5 times, then exits with error. - nsd-checkconf can lookup key secrets by name from a config file. - difffile option is always set in options struct with default or config value. - nsd-patch uses dnames to compare zone names (for trailing .). - nsdc updated to work with config file. 26 June 2006: Wouter - Nicer check in autoconf for struct timespec type. - NSEC3 next hashed ownername is a length byte followed by data. - nsd-checkconf more quiet, clearer error message. - NSEC3 does not complain about glue records without nsec3. - nsdc work (did start, stop, running, rebuild, restart, reload, stats). 21 June 2006: Wouter - nsid commandline parsed using hex_pton routine. - unit test for hex_pton. - added include stdlib, needed for free() on sunos4. - fixup of disable-ipv6 compilation. - memmove compat implementation (created fresh). - yy_set_bol() for old flex compat define. - compat implementation from openssh4.3p2 for strlcpy, inet_aton, and inet_ntop routines. - changed ctime_r usage to ctime() call, nsd is not threaded. - compiles on SunOS4/gcc-2.95. - debug statements go to the log_msg route instead of the fprintf route, so they will get to a nice logfile even if we forked away, with xfrd. logfile=/dev/stderr gives old way. - minor changes to cutest to make unit test compile on SunOS4/gcc-2.95, it checks out fine there. 20 June 2006: Wouter - updated configure to disable -O2 on platforms where gcc does not like it (such as dec-alpha). - nsd-notify used recvfrom and passed addrinfo.ai_addrlen which is a size_t, but recfrom needs a socklen_t*. On dec alpha these types differ in size (size_t is 64bit, socklen_t is 32bit). Therefore, used a wrapper variable to pass to recvfrom. - changed long int to time_t in nsd-patch.c to please compiler on dec alpha. - dec alpha complains if statements are in front of variable definitions. Fixed code for some mixups on this. - Fixup cutest for dec alpha. Code, lowercase filename, %lf->%f. - cutest fixup uses (size_t) cast and %zx to print ptrs (for debug). - for SunOS4 configure detects ssize_t and struct timespec. - removed usage of fpos_t, instead using fseeko/ftello for 64bit. - configure will define fseeko/ftello with fseek/ftell if unavailable. - added missing include from buffer.c (stdlib for free()). - defines for snprintf and vsnprintf in config.h if needed. - configlexer flex is called more cleanly with -t to write stdout. - missing include from configparser, stdlib for atoi. - config.h provide inet_pton define if it is not available. - fixup of INET6 defines, where sockaddr_storage is used outside of INET6 defines, in xfrd-tcp. - edns_init_nsid was not defined in edns.h. - added compat/fake-rfc2553.c and h from openssh 4.3p2. That has a BSD license as well. They replace getaddrinfo() (and friends) when those are missing. 19 June 2006: Wouter - updated the tpkg/manual tests for NSD 3 config files. Some need root privileges to run (using hping), they all pass. - also the tpkg/long test bug_sighup. - nsec3 code will warn at prehash time for missing exact nsec3 records. So faulty signed zones are more easily spotted. - fixed NSEC3 and CNAME/DNAME chains, it will disprove the new qname. - removed for() look in CNAME processing, only first CNAME is processed now. - zonec will error on a zone with multiple CNAMEs for one name. 16 June 2006: Wouter - Swapped read and write ops in xfrd_handle_ipc, so that a read of a signal from main can stop further writes. - xfrd will complete its last message before shutting down the ipc writes and then acknowledge the reload-sync. This resolves the race where half of ipc messages caused bad modes from the main. 15 June 2006: Wouter - In preparation of notify send overhaul, moved the notify send code to xfrd-notify.c and h files. - created cleaner split of notify send and xfr code. Still in the xfr process, because it is a convenient location. - fixed bug where notify sending would read from wrong fd. - send master zone notifies. Does not skips master zone SOA INFO updates. - fixed bug where port number acls did not match. - fixed bug where tsig keys are checked for twice, but not error_code. - fixed notify send retry counting. - added test tpkg for notifies from nsd master to nsd slave. - nsd-checkconf flags if you set allow-notify without request-xfr. 14 June 2006: Wouter - fixed crash bug when dnssec/NSEC enabled and query DNAME target did not exist. 13 June 2006: Wouter - created doc subdirectory for documentation. - removed unused DIFF FILE MAGIC string. 12 June 2006: Wouter - dname_test tpkg with very extensive DNAME testing. - moved sizes of zone_name buffers to 3072 - for escaped names. - nsd-patch has a debug option to list the contents of the difffile/ixfr.db/transfer patch log in a journal fashion. You can then manually inspect the contents. 9 June 2006: Wouter - after a reload NSD will report the memory churn: number of bytes of memory wasted by the zone transfer code. 8 June 2006: Wouter - When zone is re-chosen after a CNAME/DNAME no SERVFAIL is set, noerror is returned instead. - zonec will error on multiple DNAMEs for the same name. - zonec will error on DNAME and CNAME together. - improved loop log message. 7 June 2006: Wouter - after DNAME the closest_match is set correctly for another DNAME. - in case of a loop returns gracefully instead of crash. - nsec3 checks if it is enabled for the zone for wildcards. - NSD will give referrals for zone cuts encountered after a CNAME or a DNAME. This also fixed various subtle stuff with CNAME/DNAME and TYPE_DS at zone cuts. It basically re-determines the zone to use after the CNAME/DNAME. 6 June 2066: Wouter - zonec checks for data below a DNAME, and will not create the db, as per rfc 2672. Tpkg test to make sure such a zone is not loaded. - updated rr-test tpkg so it has no data below a DNAME. - DNAME synthesis of CNAME records, including compression for cname. - included cname creation in dname test. - preallocate the extra temporary domain_type structures. - too many temp domains returns OK packet so that the resolver will recurse and ask us again with the last name in the chain. - fixed bug introduced in preallocation on temp domain numbering. 2 June 2006: Wouter - dname_replace function that does DNAME replace and unit tests. - added error codes from DNSUPD rfc2136 to constants in dns.h. - in query.c added DNAME following code. - fixed bug 134: hints[i] in nsd.c to hints[0]. - added tpkg small test for DNAME. - tpkg to test bug 134 (starts 100 processes). 1 June 2006: Wouter - tsig test with NSD master and NSD slave server. Tsig AXFR transfer. nsd-xfer used to test slave zone contents. - fixed bug where buffer_flip() is done before appending tsig rr. - version printed at start of nsd in logfile. - xfrd prints name of tsig key used during transfer in commit comments so it appears in the log file and in zonefile after nsd-patch. - prints RRs from diff file only if debug level >= 1. - scalable transfer test xfr_gig added, you can set the size to try in the .pre file. Now set very small. 31 May 2006: Wouter - xfrd check for failed updates. It compares the time it wrote the commit to disk with the time of the last reload command. Failed updates are restarted like the zone is notified of the soa. It also catches reloads that have been lost (reload cmd while reload is running, or a crashed reload process, for example). - when reload is issued, times at that second are put back one second, so that after a reload all the zones that should have been loaded have a time from before the reload. - if a reload crashes, NSD will continue with the old database, xfrd is not informed, since it cannot fix that. - nsd-checkconf strdups arg strings before writing to it. - tsig error replies contain error data, but no signature. also crashproof, badly formatted tsigs get a format error. - tsig error print knows about DNS rcodes in tsig error field. - added tpkg tests for tsig. - tpkg test for nsd-xfer with TSIG from nsd. - small stuff with makedist.sh, CREDITS, Features, make test. 30 May 2006: Wouter - tsig pre-allocs the rr_region, not at runtime, tsig_create_record(). - redid some region work for tsig. Now has another temporary region for the context data. User is only aware of the region passed at start that exists for the lifetime of the struct. During TSIG checks no more mallocs are done, only region_free_all and region allocs (of small size). - checkconf, port is stored as a string. - tsig now keeps a max_digest_size for giving reserved space. - AXFR does tsig every 96 packets (and first and last packet). - tsig signing works for all queries. SOA queries, ... If you configured the key in the config file, you can use that key for any query for any zone. Except for NOTIFY and AXFR queries; those are only allowed for the zone (and source ip address) which are configured in the config. - cleaner compile with tsig disabled. - fixed unknown key error reply in tsig. 29 May 2006: Wouter - The nonblocking write routines disable silently if they have nothing to do. - put xfrd read/write state routines (almost 500 lines of code) into xfrd-disk.c file. - little readme blurb on xfrd state file for the operator. - put ipc code in its own file for ease of reading. - removed --disable-axfr, you can control this via acls. With no provide-xfr: statements, a zone will not do axfr. 25 May 2006: Wouter - fixed reload sending; it checks for EAGAIN and EINTR. - reload sends parent quit command blocking to make sure of arrival. - send_children_quit in parent uses nonblocking writes and closes the pipe to signal the child to quit (even if the write does not come through, the closed pipe will cause the child to quit). - need_to_send_STATS flag in parent. - reload has its own ipc-listening handler in server_main. - nonblocking writes for server_main; this solved write-blocking race. - another race condition solved, if a process dies, half a read or write buffer could be left behind on another process. These are dropped. Now: * The server_main drops ipc from dead children. * The server_main drops ipc if xfrd dies. * The server_main drops xfrd(old) and all children ipc on reload. * The xfrd drops ipc to parent on a SOA_BEGIN from reload. So after reload, but parent and xfrd start with clean ipc buffers. 24 May 2006: Wouter - unit tests print progress while running to stderr. Included license of cutest with its source in svn repository. - stack type (for the IPC buffer of zone update dirty). And unit test. - only update zone-is_ok if needed to reduce memory copy on write. - split off conn_write() from xfrd tcp nonblocking write routines. - nonblocking writes for xfrd. 22 May 2006: Wouter - ported over minor nits from 2.3.5 NSD fixups. Cast to (void) unused function return values. - removed kill signal to children, superfluous due to quit cmd ipc. - moved is_ok for zones to the zone_type in namedb, not in the options, it is a runtime value not a config value. For zones that have no data, parent and children keep no state. 12 May 2006: Wouter - fixed up usage print for zonec to include -f option. - xfrd send notifies. - server no longer sends SOA INFO for master zones. - removed possible debug log print of a null string. 11 May 2006: Wouter - nsd.conf.sample shows defaults for ip4-only, ip6-only and debug-mode. - SOA_BEGIN message on start of reload sending soa info so that xfrd will not reply with expire-notifications and thus deadlock both on blocking writes (and no OS buffer on the pipes). 10 May 2006: Wouter - nsdc.sh is set +x after creation. - improved error message when zone in db has no config info. - support for broken nsec3 chains (if the one with the SOA bit is complete, it is OK for there to be other nsec3 chains with different parameters in the zone). 9 May 2006: Wouter - Fix for finding bad zone when populating SOA info on start. it would find a parent zone instead of the zone in question ( which is empty). - request-xfr: AXFR 10.0.0.153 keytouse syntax to interoperate with NSD machines. Will only send AXFR queries to the machine. - documented AXFR option in nsd.conf.5 manual page, and updated nsd-checkconf, nsd.conf.sample. - made 'skipping zone' log entry clearer (Sam Weiler asked). 8 May 2006: Wouter - updated zparser.y to handle empty nsec_seq lists. for empty nonterminals in NSEC3. - nicer without ambiguous grammar. 5 May 2006: Wouter - nsd-notify handles option -y key:secret to TSIG sign outgoing queries. - the acl checks now verify TSIG signatures on the query. - iterated_hash compiles with ssl disabled. - new ipc NSD_ZONE_STATE sent by xfrd to nsd process. notifies nsd of the state (ok or expired) of a zone. - reload process waits for the old server_main to exit to make sure there is no race condition listening to the NSD_ZONE_STATE messages generated when reload sends SOA_INFO to xfrd. - server_main and children all set zone_ok state in config options. also server_main so that newly forked children get the right state. - if a secondary zone is expired, NSD returns SERVFAIL. a transient error, so resolvers try again later. - SOA_END ipc message, sent by reload to xfrd, so it can repeat all zone states (which can have changed during reload). - zone_is_ok kept in config section so that state for zones without data is not lost. Those have no zone_type*. - secondary zones start in the expired state. - if expired zones are updated, then NSD gets the go ahead from xfrd after reload sends SOAINFO/SOAEND msg, so it is really updated in nsd memory. - fixed tpkg xfr_1 to have longer expiry times (from 0 and 3 seconds to 2000 and 3000 seconds), so the zone does not expire during the test anymore. 4 May 2006: Wouter - when a new lease is acquired xfrd_packet_newlease result is used. - if a zone is lost in nsd db, xfrd will update state to match. - IXFR can use TSIG in queries and verify responses. - Fixed memory leak in xfrd tsig handling. 3 May 2006: Wouter - forward of 2.3.4 RELNOTES into trunk. - debug log statements to track xfrd request rounds. - removed memleak from handle_passed_packet in xfrd. - faster find_zone in difffile.c. - nsd-patch writes commit log entries into zone file. - took some tsig.c enhancements from 3 branch, -> if key or algo changes during connection, return bad_key, -> debug statement neater. - nsd adds tsig keys to tsig keyring at startup. 2 May 2006: Wouter - ifdef inet6 back on ss_family usage in server.c. - nsd-checkconf ip6 ifdefs improved. - xfrd tries servers 3 rounds, then waits for next retry. 1 May 2006: Wouter - off_t used for 64bit fileio. - searches for smallest unused part and sets diff_skip to that. - doc comment near the region_free_all for every query about malloc speed. - null ptr in strcmp does not work on bsd, fixed nsd-checkconf. - made nsd.conf.sample.in so the sample gets prefix-corrected. - removed nsd.zones.sample. - makedist.sh added manual pages for nsd-xfer nsd-patch. - install/uninstall nsd-patch, nsd-checkconf and manpage. small update readme. 28 Apr 2006: Wouter - ixfr >64k in xfrd. - fixed length of new commit parts. - fixed multiple ipc reads in xfrd. - fixed multiple packet ixfr read in diff file. Miek: - Forward port fixes for nsd-xfer and nsd-notify 27 Apr 2006: Wouter: - nsec3 review fixes. - diff file format expanded for >64kb transfer support. - diff reader adjusted for >64kb. Jelte: - small non-null options check in nsd.c. Miek: - updated nsd-checkconf for zone parse shell script support. 25 Apr 2006: Wouter - Tests on NSEC3 code. Fixed that the unsecure delegations also have _ds_ parent nsec3 prehashes, so that they get proper NSEC3s. NSD will serve NSEC3s to prove 'opt-out' also if the opt-out bit is (erroneously) not set. - For the 05pre2 draft section 5.4.8.1. QTYPE is NSEC3, only NSEC3 RRsets at name. Fixed that RRSIGs present do not matter. And also the closest encloser proof in that case fixed. If wildcard exists below zone apex servfails (cannot disprove it and NSD cannot instantiate the wildcard at that point). 24 Apr 2006: Miek Miek: - forward port nsid (disabled by default) Wouter: - nsd-patch manual page. - minor MacOSX port fixes. - xfrd-reload-timeout: config option. - if you set the xfrd reload timeout to -1 it will not automatically reload after a transfer. User can reload. - reload timeout is a wait period after the reload is triggered. - more verbose acl logging. Validated acls are logged in detail. Invalid acls are only logged in debug mode, level >= 1. - log message when xfrd tcp connections max out. - if unknown NSEC3 hash type (not SHA-1), disable NSEC3. - xfrd randomizes the timeouts, within 10% of original, to spread out activity. Short timeouts < 10 seconds are not affected, and will give activity bursts (on startup for example). 21 Apr 2006: Wouter - put NSEC3 code in nsec3.c and nsec3.h. - iterated_hash only adds the salt if salt_len > 0. - added some assertions and cleanups to nsec3 code. - prehash also calcs the nsec3_last domain*. - dbaccess when reading in will set the rr_type.owner value. - changed namedb_find_zone to domain_find_zone, log msgs. - implemented logic from nsec draft 05-pre2 section 5.4.1 - 5.4.8. NSEC3 responses only happen for nsd compiled with --enable-nsec3 and for zones where an NSEC3 with the SOA bit set exists. - added prehash pointer to ds parent side cover for opt out. - removed dynamic plugins. Dynamic plugin support is an explicit non-requirement (under creeping featurism). - in domain table create root nsec3 ptrs are NULL. 20 Apr 2006: Wouter - Unittest of base 32 encoding. - unittest start for iterated hash. - fixed for ctrlc in debug mode. - delete zparser_conv_long, not used, not needed - nsd-xfer will display NSEC3 correctly. zonec parses. - improved usage() line from zonec, about -c none, must be -C. - base32 printed in lowercase (canonical format for DNS). - NSEC3 added prehash pointers to the namedb. - NSEC3 autodetects presence of NSEC3 in zone and parameters. 19 Apr 2006: Wouter - port fix base10 in zonec conv short from 2_2 branch to trunk. and conv byte, algo, certificate, long. - configure option to enable NSEC3 (--enable-nsec3) support. - from Ben Laurie's NSEC3 patch, loaned the parse code, base32 conversion code and iterated_hash. With some small modifications. The type rrdescriptors are indexed by value below SPF, and in rdata_wireformat_to_rdata_atoms BINARYWITHLENGTH checks for end of buffer. Also parser checks for '-' salt. Some layout (spaces after ,s). And NSEC3 define is used. strtol used for iterations is base 10. - moved rrtype descriptor table sanity check to unittest. 18 Apr 2006: Wouter - Fixed check for SOA IN, bad ntohs in the check. - minimum timeout also enforced for very low expire times. - report the actual used length of the sockaddr to sento for FreeBSD. 7 Apr 2006: Wouter - modified the kill_nsd tpkg so that it waits up to 10x5 secs for nsd to make the pid file, and it wait up to 10x5 secs for nsd to exit after the kill signal is given. - xfrd checks on startup if there is trailing garbage in the diff file, left there by a previous xfrd killed in action. It then snips off any partial parts, so service can resume. Also the difffile_skip pos is set before any partial record there. - first version of nsd-patch; reads db and ixfrs and updates zones. - moved print_rdata from nsd-xfer to rdata.h to share code. - moved print_rr from nsd-xfer to util.h to share code. 6 Apr 2006: Wouter - notify handler passes acl number that matches to xfrd. - xfrd keeps a next_master for a zone, and sets it after notify. when notified nsd will try to contact the master that sent the notify, if send from an address that is both in acl allow-notify and request-xfr. - xfrd closes its tcp and udp sockets on exit. - default names for diff file and xfrd state nicer. - fixed up kill nsd grep on ps. - fixed up race conditions in test script for kill nsd wait for pid file creation by nsd, and grep -v grep in check. - in nsd signal-flags inherited from the parent are zeroed when a server_child starts. Also the server_child switches back to NSD_RUN mode when a bad mode happens. - check if ixfrs start from the version in memory. - if IXFR/AXFR ends in a serial that is newer than the serial that was sent in an notify, update the notified serial. 5 Apr 2006: Wouter - added lowerbound for retry timeout. - added extra assertions to xfrd-tcp.c, saying that the waiting line for tcp connections must be empty if the counter is below max. - setup so that the first master tried is the first in acl list. - diff file skips OPT and TSIG RRs if they are put into the answer section. - if IXFR contains an RR to delete that does not exist, nothing happens. - update zone for NS, RRSIG also if multiple RRs in the rrset. - difffile: create zone struct also if domain exists already. - difffile: destroy temp region on error. - difffile: in delete_RR, create temp region outside of the routine, so no alloc region, destroy region for every deleted RR. - difffile: for IXFR: do not delete final SOA RR. - difffile: unknown parts in file is an error. - difffile: EOF on last packet is ignored w/o giving an error. 4 Apr 2006: Wouter - Addes EACCES to the netio dispatch error bailout. - Removed EACCESS (probably due to log_msg), error on close xfrd pipe is small, main process closes its end, and hopes for the best). - review: return on error condition in xfrd_tcp_open fixed. - review: expired when time >= expire_time, so it will not wait for the retry after expire until it will detect the expiredness. - removed duplicate lines from xfrd_handle_zone_timeout. - review: copy of uint32_t using memcpy to avoid unaligned memory accesses. - review: fd=-1 removed from set_refresh_now; only does timer. - on a tcp timeout it will retry immediately (instead of waiting another retry timeout). This means if you set refresh_now, it will interrupt a tcp-timer for a fresh retry with the next master. - put null in buffer for xfrd read state. - log msg uses string that exists instead of overwritten buffer. - read entry sets refresh depending on current time, and makes sure not to check soa contents if none provided. added explanatory comments. - EACCES back in check. - server_main first checks for terminated children, then select(). So when select is interrupted, by kill or quitting children, it will first see if it has to quit itself, before restarting the children. - destroy tempregion xfrd read on error. - check for serial existence in xfrd_handle_incoming_soa. - handle_incoming_soa uses set_timer_refresh routine. and can handle expire times < refresh times. - log msg for udp socket() error. - review: xfrd_parse_soa_info email parse uses correct buffer spot. - added a lowerbound to refresh interval (=1 second now). - upon receipt of a IXFR, if the serial is older than the notified serial, the zone stays refreshing (but the ixfr is saved). 3 Apr 2006: Wouter - Added buffer length check to internal ipc. - split out packet_read_query_section from the process_query_section routine (and moved to packet.c/h). - xfrd reads passed packet via ipc. - ported over fix to 2_2 on missing rr types by removing the duplicate RRtype array, and using rrtype_to_string. - xfrd handles notifies. immediately starts updating. - xfrd state file format fix. - removed libwrap stuff - superseded by acls. use provide-xfr: statements for your zone in the config file. updated README for this. - updated tpkg tests for axfr to use provide-xfr: 127.0.0.1 NOKEY - review: move var create to start of function (xfrd_init()). 31 Mar 2006: Wouter - zone type has a pointer to zone options. - nsd options has an rbtree to find zone options in. - nsd checks acl for incoming notifies and replies error or confirmation. - nicer layout in options.c. - updated makefile dependencies. - fixed sz for SOA_INFO ipc, which was too small. - notify is sent to server_main, server_main sends it to xfrd. 30 Mar 2006: Wouter - include: documented in manual page. - MAXINCLUDES define in one place (config.h). - configure checks for strptime in include files. - use %d instead of %zd (sparc5 machine does not get zd). - use region_strdup in configlexer. - added a check for EINVAL in dispatch - will abort on the error instead of busy hang. 29 Mar 2006: Wouter - \r for config lexer. (similar changes to zonelexer). - forward port of fix to 2_2 branch: short int in var_arg is promoted to int, according to B. Laurie. The same logic for %o, %d %x would hold for %u I think. - in XFRD, soa prim_ns and email domain names are kept in a max size buffer. - split up dname_parse into parse from string to wireformat and parse from wireformat to memoryformat, so both can be called. - split up dname_make_from_packet into reading the wireformat from the packet and the dname_make, so both can be called. - xfrd reads all soa info from incoming xfr packets. - xfrd will ignore TC bit on tcp channels. - nsd sends xfrd all soa info, including ttl and dnames. - config file now has an include: filename directive. 28 Mar 2006: Miek - forward port fixes for zone compiler and \r. svn:1926-1927 - add DO bit MASK and remove the !! construct 17 Mar 2006: Wouter - according to axfr-clarify, added comments that we check more leniently on further responses on a TCP stream. 16 Mar 2006: Wouter - Fixed up SOA INFO Send routines. Send from server works. - niced up xfrd state file. - Fixed up so that after a reload it will continue in diff file where it left off. - made send of SOA info use write_socket, in case of short writes. - redesigned xfrd_tcp_read to use the same code for ipc read. - no free()s before xfrd exit. - xfrd handles incoming SOA INFO ipc packets. - removed debug, updated zones get SOA INFO sent. 15 Mar 2006: Wouter - Fixed up domain table insert, it was being used in routines that originate from nsd-xfer that do not set compression numbers correctly. - memleak fix in difffile in case of error. - difffile processing works so that NSD can read an axfr saved into the nsd.diff file. (xfrd already request and save it there). - split off xfrd tcp handling into xfrd-tcp.c. - cleaned up send_udp in xfrd, and read_state. - removed xfrd tcp_send_blocking. - xfrd sets state from ok to refresh to expired based on timeout. - xfrd sets reload timeout. - Added zone updated to keep track of zones that are changed after a reload. These zones get their information notified to xfrd. - removed unused zprintrr declaration from zonec.h - nsd sends soa information to xfrd. 14 Mar 2006: Wouter - TODO updated - worked on reload ixfr. It will add/delete RRs and zones. - xfrd receive parse of xfr messages improved. writes commit. - server compressed_dname_offsets table is increased if reload creates extra names. - difffile will create zone and apex if not there (i.e. the zone is configured but no data file provided). - bit more verbose in error message for bad diff file. - Typo fix in sample config file. 13 Mar 2006: Wouter - configure sets fseek (fgetpos/fsetpos) to use 64 bit interface with _FILE_OFFSET_BITS=64. - nsd will skip loading the .db if the DB checksum is the same. - Miek added trace test and nsd kill test. - Wouter worked on diff file c. 10 Mar 2006: Wouter - Cleanup of UDP/TCP code in XFRD. - xfrd now has tcp max connections and managing. tcp read/write. - response TC on UDP ixfr, starts TCP. - sends correct ixfr and axfr queries, a bind server answers. - made packet_skip_dname() public. - sets read/write event flags for tcp fd right. 9 Mar 2006: Wouter - Removed header from DIFF file format. CRC not that important there, you have to check the packets anyway. - cutest rbtree removed unused clean_rbtree and always_fail routines. - xfrd timeout handler, more work. Checks expire. 8 Mar 2006: Wouter - xfrd sends UDP xfr request to master(s) with timeouts, and stores returned data on disk. - updated dependencies and declaration of write_soa_buffer. 7 Mar 2006: Wouter - Fixed printfs for size_t warnings on Mac OsX. 6 Mar 2006: nsd-team * Wouter: xfrd read and write work. Statefile is "nsd.xfst". * Wouter: nsd-checkconf checks dname parse of zone name:. * Wouter: updated difffile in parser.y, production in server: clause. * Wouter: zonec now takes -C for 'no config file' option. * Wouter: updated configyyrename.h for bison 1.875d on sparc. * Miek: zonec -h and nsd -h exit with exit code = 0. * Miek & Wouter: updated tpkgs to work again. * Wouter: xfrd read handle soas, handle soa_incoming part. * Wouter: moved compare_serial() from nsd-xfer to util.h. 4 Mar 2006: Wouter - xfrd zone and soa memory structure definitions. - xfrd init zones. - xfrd read and write state file code. - option for difffile: and xfrdfile: config lines. 3 Mar 2006: Wouter - Removed double kill after reload. Only socket cmd send. - Added code to handle race condition where xfrd is restarted during a successful reload. Afterwards, the new server_main only has the old xfrd pid, new xfrd is an orphan. Solution: when xfrd closes cmd channel (i.e. it quit) unexpectedly, send sighup to all processes in the group. This should quit the orphan & all children & reload the server_main, which will fork the children and xfrd again. 2 Mar 2006: Wouter - Added nsd-checkconf.8 to makedist.sh replace list. - DIFF file format updated. - removed tsigkey->server value, it was read in, but unused. - new function to add config file keys to tsig. - nsd-checkconf checks parsing of keys. - Updated sample key file with valid keys. - added first xfrd files. xfrd is started from server_main. xfrd listens to server and server to xfrd. xfrd is restarted if it dies unexpectedly. xfrd quits when server signals it. xfrd survives nsd reloads. - nsd_options no longer global variable. 1 Mar 2006: Wouter - Nicer text in nsd.8. - nsd.c prettier code in option handling. - zonec.c code prettier in option handling, also chdir bug removed. zonec uses the zone definitions in the config file. updated zonec.8 and usage(). - nsd also chdirs to the zonedir, otherwise nsd and zonec would try to read the database: file from different directories. .(it does the chdir before the chroot call.) - new calling syntax for zonec and nsd, because of new config file. - options added acl acceptance tests (no tsig yet). - added unit test for options.c - for acl tests. - zonec removed unused vars, nsd-checkconf print arguments. - nsd-checkconf.8 manual page. 28 Feb 2006: Wouter - checked in options.h and config parser code. - also nsd-checkconf that will test a config file .(and optionally show what was read). - default identity has a spelling error. - Small fix (typo in example) to config manual page. - Added ; to configparser.y to please bison 1.75 on bsd. - Will check for blocked addresses in outgoing acls. Also ranges. - Check configuration tpkg test added. Uses checkconf. - checkconf does extra semantic tests. i.e. enable absent features. - tcpcount and servercount cannot be negative. - updated nsd.conf.5 manpage for @port syntax. - changed config parser: allows empty server: part (defaults). - made nsd.conf.sample file. - put option to configure for CONFIG_FILE nsd.conf location. Note. Already nsdc.conf exists. Both exist now. - updated makefile dependencies (gcc -MM). - getopt optstring in nsd-checkconf updated ("v" only option). - Added config .o files to nsd and zonec. This compiles. - Added commandline option -c configfile to zonec and nsd. configure defaults < configfile < commandline options in importance. 24 Feb 2006: Wouter - Added compute_crc in util.h and unit tests for it. - in cutest.tpkg the number of unit tests was hardcoded in the tpkg package. Removed the dependency, cutest exit value indicates if any failures happened. - Added crc at end of NSD-database format. Unique per db. upped db version to 7 because of this. - Tested that crcs are big/little endian correct. - Added DIFF file spec - updated tpkg213 which compares md5 on a zonefile for new format. - added nsd.conf.5 manual page with a draft contents. 22 Feb 2006: nsd-team * Miek: Changed over to Cutest testing framework. * Miek: fixed typo in netio.h * Miek: fix syntax in rbtree.c put functions on multiple lines. * Miek: unit test tpkg for cutest. * Wouter: fixed ptr bug in rbtree unit test. 17 Feb 2006: Wouter - rbtree_delete is added and works. Unit tests are there too. - Changed tail recursion in rbtree_delete to while loop. - Tagged this version as NSD_3_signalsocket_solution. It is the stable 2_2 branch with cleanups, portable, and signalhandler solution by socket communication redesign. 15 Feb 2006: nsd-team * Wouter: Fixed server_child would wait for two kill signals before quit. * Miek: don't check for port==0 pkt, just try to send them. Forward Port of 2.3. * Wouter: Removed unused, not substituted, @nsdxfer@ from Makefile.in. 14 Feb 2006: Wouter - Added unit tests for rbtree. Extensive testing of all functions. - Added tpkg unit test. - configure tests for CUnit(optional lib for unit tests). Makefile cleanup so it works on non-gmake on freebsd. 13 Feb 2006: Wouter - Removed timespec_add(current_time) in server_main, the timeout was relative, not absolute. This fixes EINVAL on the timeout on freebsd. - Added check in configure for compiler flags. Used for -Wextra. - Added check in configure for va_list definition conflict between stdio and stdarg. This happens on DEC Alpha/Debian. - removed --enable-mmap configure option. There is no mmap support in the current codebase. - renamed local prev to next in domain_next() in namedb.h. - Removed heap.h. It was not used. Heap and rbtree are mingled anyway. - in netio.c, in dispatch, it would store the next pointer 'in case the handler removes itself'. But if the handler removes that next. Then it would fail. So stored the next in struct netio. This removes a potential bug. Netio_dispatch is not reentrant. Reentry would need a list of iterator* in struct netio. - Changed process_query() to server_process_query(). It is too similar to query_process(). 10 Feb 2006: nsd-team * Wouter: Improved configure.ac to detect pselect in sys/select. The check works on freebsd(yes) and fedoracore 3 and 4 (no). I hope it also works on Solaris. Also various other prototypes were implicit: chroot, strptime, ... These are also solved. * Wouter: Checked configure on sparc5(solaris). Added check for ctime_r in time.h (for tsig.c). This conf also works on freebsd/linux. * Wouter: Updated dependencies in makefile for plugin headers. These are included only when --enable-plugins is present. * Wouter: Added a send quit over socket to kill commands in server_main, These act when the fork children fails. If the kill fails, the socket command hopefully still works. * Wouter: Put reload code into a separate function. It communicates with a socket to the old parent, and sends it a quit command. This works and terminates the old nsd. Left in the kill as a double failsafe. If the reload process dies, then the parent closes the socket. * Wouter: Separated the signal mode from the socket-determined nsd->mode. Every signal function has a variable, so that multiple signals can arrive. Only the number of signals of the same type is lost, but not important for nsd. The signals are handled in turn by the run loop. This completes the coding to remove signal race conditions: - nsd uses sockets to communicate with its subprocesses(server,reload). - signal handler routine contains no lengthy system calls. - signals cannot overwrite a previous signal. * Wouter: fixed problem where nsd->mode and mode are different in server_main. Nsd would kill the children, but then restart them again. 09 Feb 2006: nsd-team * Wouter: Updated dependencies in Makefile (regenerated them with gcc -MM). * Wouter: Used splint on the source (with settings to reduce spam.) And came to the following changes: - In util.h, make it respect HAVE_CONFIG_H and HAVE_SYSLOG_H. Also it now defines fallback values for #defines in syslog h. - Added explicit cast to (unsigned int) in snprintf in dname.c, dname_to_string routine. * Wouter: Used extra warnings during gcc compile. -Wextra -Wall -pedantic -Wbad-function-cast -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wstrict-prototypes -Wdeclaration-after-statement. Using -Wtraditional gives too many warnings. * Wouter: Found a problem with pselect. sys/select.h does not by default provide the pselect function definition. configure script is adjusted to test for this and enable _XOPEN_SOURCE=600 to get it. Found this using the gcc warnings. * Wouter: dname and rbtree test apps were in make clean target, but do not exist anymore. Removed from make clean target. * Wouter: in util log_file() the epoch time_t is passed to printf without an int cast. Found using extra gcc warnings. * Wouter: In server.c fixed some signed-unsigned comparisons using the extra gcc warnings. - in shutdown and int was used instead of size_t. - in server_main timeout(signed) was compared with unsigned. - unused variable in new handler functions. - in handle_child_command int i instead of size_t was used. - in zonec the process_rr routine was missing (void) as paramlist. * Wouter: Added -Wall and -Wextra when --enable-checking is enabled. * Miek: Ported over the big fat enable checking configure warning. * Wouter: fixed configure check for pselect on freebsd. 08 Feb 2006: nsd-team * Wouter: In server.c also sockets from unexpectedly dead childs are closed. * Wouter: in nsd.c and server.c cleaned out the signal handler, so that it only includes two switch/if statements and alters only the mode. No more calls to alarm(), waitpid(), write(), log_msg(). Instead the work is done in the runloop in server.c and sent by socket. Also the parent now waits for children. Parent restarts them. * Wouter: Fixup, the children will quit if the parent closes the command socket. If parent is killed, they will exit too. * Wouter: The server_main now listens to children command channels. Included timeout to check for terminated processes. Test says that new signal handler works, and child->parent comm. 07 Feb 2006: nsd-team * Miek: configure.ac version to 3.0.0 * Miek: looked at: buffer.{ch}, answer.{ch}, dns.{ch} those files don't have any changes, except for dns.{ch} for the explicit compression. * Miek: looked at: zlexer.lex and zparser.y; only changes there for the database changes. * Wouter: Changed buffer in write_pid from 16 bytes to 32 bytes, this makes 64 bit numbers fit in the buffer. * Wouter: Socket connection between parent and child nsds added. But sighandler now in worse shape. Need to close them. Remove kills. * Wouter: close the parent and child command channel sockets in shutdown(). nsd-4.1.26/doc/NEW-CFG-OPTION0000664000175000017500000000470512136154564014567 0ustar wouterwouterWhen adding a new configuration option to NSD, several files need to be touched. This file is an enumeration of files that need to be edited. Suppose we are going to add a configuration option 'dummy:' that can take a string. We need to update the following files: 1. configlexer.lex 2. configparser.y 3. options.h 4. options.c 5. nsd.conf.sample.in 6. nsd.conf.5.in 7. nsd-checkconf.c 8. tpkg/checkconf.tpkg 1. Update configlexer.lex Make sure that zonec understands the new option by adding the following line into configlexer.lex dummy{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DUMMY;} 2. Update configparser.y Make sure that zonec can parse the new option by adding VAR_DUMMY to the set of tokens: %token VAR_DUMMY Update the grammar. For example, if it a server option, extend content_server: content_server: server_ip_address | ... server_hide_version | server_dummy; And write down the dummy rule: server_dummy: VAR_DUMMY STRING { OUTYY(("P(server_dummy:%s)\n", $2)); cfg_parser->opt->dummy = region_strdup(cfg_parser->opt->region, $2); } ; 3. Update options.h Make sure that there is storage for the dummy option. In struct nsd_options, add: const char* dummy; 4. Update options.c Set a default dummy string. In the function nsd_options_create(), add: opt->dummy = "dummy"; 5. Update nsd.conf.sample.in Add a reference in the sample configuration file: # This option does nothing. # dummy: "dummy" 6. Update nsd.conf.5.in Update the nsd.conf manpage: .TP .B dummy:\fR Does nothing. 7. Update nsd-checkconf.c Make the checkconf tool aware of the new option. In config_print_zone(), add: SERV_GET_STR(dummy, o); and in config_test_print_server(), add: print_string_var("dummy:", opt->dummy); 8. Update tpkg/checkconf.tpkg Make the test aware of the new option. Extract checkconf.tpkg: $ cd tpkg; $ tpkg extract checkconf.tpkg $ cd checkconf.dir And add to the various checkconf.check[1-9] files: dummy: "dummy" Go back to the tpkg directory and create the new test: $ cd .. $ tpkg create checkconf.tpkg 9. Update other files You might need to edit other files too: - If the new option requires to be enabled at build time, you need to add stuff to configure.ac and Makefile.in. - Update documentation files, like doc/README, doc/RELNOTES, doc/Changelog. - Obviously, the source code files need to be edited to implement the new functionality. nsd-4.1.26/compat/0000775000175000017500000000000013401455024013307 5ustar wouterwouternsd-4.1.26/compat/strlcat.c0000664000175000017500000000461711325543420015140 0ustar wouterwouter/* compat/strlcat.c */ /*- * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ #include #ifndef HAVE_STRLCAT #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* !HAVE_STRLCAT */ nsd-4.1.26/compat/basename.c0000664000175000017500000000044207434720207015235 0ustar wouterwouter/* Return the basename of a pathname. This file is in the public domain. */ char * basename (name) const char *name; { const char *base; for (base = name; *name; name++) { if (*name == '/') { base = name + 1; } } return (char *) base; } nsd-4.1.26/compat/memcmp.c0000664000175000017500000000073111761673212014742 0ustar wouterwouter/* * memcmp.c: memcmp compat implementation. * * Copyright (c) 2010, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #include int memcmp(const void *x, const void *y, size_t n); int memcmp(const void *x, const void *y, size_t n) { const uint8_t* x8 = (const uint8_t*)x; const uint8_t* y8 = (const uint8_t*)y; size_t i; for(i=0; i y8[i]) return 1; } return 0; } nsd-4.1.26/compat/memcmp.h0000664000175000017500000000047511714737525014762 0ustar wouterwouter/* * memcmp.h: undef memcmp for compat. * * Copyright (c) 2012, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #ifndef COMPAT_MEMCMP_H #define COMPAT_MEMCMP_H #ifdef memcmp /* undef here otherwise autoheader messes it up in config.h */ # undef memcmp #endif #endif /* COMPAT_MEMCMP_H */ nsd-4.1.26/compat/inet_pton.c0000664000175000017500000001214210446177505015465 0ustar wouterwouter/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ /* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include #include #include #include /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4 (const char *src, uint8_t *dst); static int inet_pton6 (const char *src, uint8_t *dst); /* * * The definitions we might miss. * */ #ifndef NS_INT16SZ #define NS_INT16SZ 2 #endif #ifndef NS_IN6ADDRSZ #define NS_IN6ADDRSZ 16 #endif #ifndef NS_INADDRSZ #define NS_INADDRSZ 4 #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(af, src, dst) int af; const char *src; void *dst; { switch (af) { case AF_INET: return (inet_pton4(src, dst)); case AF_INET6: return (inet_pton6(src, dst)); default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(src, dst) const char *src; uint8_t *dst; { static const char digits[] = "0123456789"; int saw_digit, octets, ch; uint8_t tmp[NS_INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { uint32_t new = *tp * 10 + (pch - digits); if (new > 255) return (0); *tp = new; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ static int inet_pton6(src, dst) const char *src; uint8_t *dst; { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; uint32_t val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } nsd-4.1.26/compat/pselect.c0000664000175000017500000000174512160052420015113 0ustar wouterwouter/* * Like select(2) but set the signals to block while waiting in * select. This version is not entirely race condition safe. Only * operating system support can make it so. */ #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include #include int pselect (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) { int result; sigset_t saved_sigmask; struct timeval saved_timeout; if (sigmask && sigprocmask(SIG_SETMASK, sigmask, &saved_sigmask) == -1) return -1; if (timeout) { saved_timeout.tv_sec = timeout->tv_sec; saved_timeout.tv_usec = timeout->tv_nsec / 1000; result = select(n, readfds, writefds, exceptfds, &saved_timeout); } else { result = select(n, readfds, writefds, exceptfds, NULL); } if (sigmask && sigprocmask(SIG_SETMASK, &saved_sigmask, NULL) == -1) return -1; return result; } nsd-4.1.26/compat/b64_pton.c0000664000175000017500000002636112475071563015132 0ustar wouterwouter/* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include #include #include #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static int b64rmap_initialized = 0; static uint8_t b64rmap[256]; static const uint8_t b64rmap_special = 0xf0; static const uint8_t b64rmap_end = 0xfd; static const uint8_t b64rmap_space = 0xfe; static const uint8_t b64rmap_invalid = 0xff; /** * Initializing the reverse map is not thread safe. * Which is fine for NSD. For now... **/ static void b64_initialize_rmap () { int i; /* Null: end of string, stop parsing */ b64rmap[0] = b64rmap_end; for (i = 1; i < 256; ++i) { /* Whitespaces */ if (isspace(i)) b64rmap[i] = b64rmap_space; /* Padding: stop parsing */ else if (i == (unsigned char)Pad64) b64rmap[i] = b64rmap_end; /* Non-base64 char */ else b64rmap[i] = b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) b64rmap[(uint8_t)Base64[i]] = i; b64rmap_initialized = 1; } static int b64_pton_do(unsigned char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = ofs << 2; state = 1; break; case 1: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex+1] = (ofs & 0x0f) << 4 ; tarindex++; state = 2; break; case 2: if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex+1] = (ofs & 0x03) << 6; tarindex++; state = 3; break; case 3: if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int b64_pton_len(unsigned char const *src) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int b64_pton(char const *src, uint8_t *target, size_t targsize) { if (!b64rmap_initialized) b64_initialize_rmap (); if (target) return b64_pton_do ((unsigned char*)src, target, targsize); else return b64_pton_len ((unsigned char*)src); } nsd-4.1.26/compat/memmove.c0000664000175000017500000000166511761673212015140 0ustar wouterwouter/* * memmove.c: memmove compat implementation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. */ #include #include void *memmove(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n) { uint8_t* from = (uint8_t*) src; uint8_t* to = (uint8_t*) dest; if (from == to || n == 0) return dest; if (to > from && to-from < (int)n) { /* to overlaps with from */ /* */ /* */ /* copy in reverse, to avoid overwriting from */ int i; for(i=n-1; i>=0; i--) to[i] = from[i]; return dest; } if (from > to && from-to < (int)n) { /* to overlaps with from */ /* */ /* */ /* copy forwards, to avoid overwriting from */ size_t i; for(i=0; i #ifndef HAVE_INET_NTOP #include #include #include #include #include #include #include #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ #endif #ifndef INT16SZ #define INT16SZ 2 /* for systems without 16-bit ints */ #endif /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static const char *inet_ntop4(const u_char *src, char *dst, size_t size); static const char *inet_ntop6(const u_char *src, char *dst, size_t size); /* char * * inet_ntop(af, src, dst, size) * convert a network format address to presentation format. * return: * pointer to presentation format address (`dst'), or NULL (see errno). * author: * Paul Vixie, 1996. */ const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET: return (inet_ntop4(src, dst, size)); case AF_INET6: return (inet_ntop6(src, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address, more or less like inet_ntoa() * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a u_char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char * inet_ntop4(const u_char *src, char *dst, size_t size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; int l; l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); if (l <= 0 || l >= (int)size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } /* const char * * inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ static const char * inet_ntop6(const u_char *src, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; char *tp, *ep; struct { int base, len; } best, cur; u_int words[IN6ADDRSZ / INT16SZ]; int i; int advance; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; ep = tmp + sizeof(tmp); for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) return (NULL); tp += strlen(tp); break; } advance = snprintf(tp, ep - tp, "%x", words[i]); if (advance <= 0 || advance >= ep - tp) return (NULL); tp += advance; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { if (tp + 1 >= ep) return (NULL); *tp++ = ':'; } if (tp + 1 >= ep) return (NULL); *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } strlcpy(dst, tmp, size); return (dst); } #endif /* !HAVE_INET_NTOP */ nsd-4.1.26/compat/fake-rfc2553.h0000664000175000017500000001241510611704136015461 0ustar wouterwouter/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */ /* * Copyright (C) 2000-2003 Damien Miller. All rights reserved. * Copyright (C) 1999 WIDE Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Pseudo-implementation of RFC2553 name / address resolution functions * * But these functions are not implemented correctly. The minimum subset * is implemented for ssh use only. For example, this routine assumes * that ai_family is AF_INET. Don't use it for another purpose. */ #ifndef _FAKE_RFC2553_H #define _FAKE_RFC2553_H #include #include #include #include #include /* * First, socket and INET6 related definitions */ #ifndef HAVE_STRUCT_SOCKADDR_STORAGE # define _SS_MAXSIZE 128 /* Implementation specific max size */ # define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr)) struct sockaddr_storage { struct sockaddr ss_sa; char __ss_pad2[_SS_PADSIZE]; }; # define ss_family ss_sa.sa_family #endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ #ifndef IN6_IS_ADDR_LOOPBACK # define IN6_IS_ADDR_LOOPBACK(a) \ (((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \ ((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == htonl(1)) #endif /* !IN6_IS_ADDR_LOOPBACK */ #ifndef HAVE_STRUCT_IN6_ADDR struct in6_addr { uint8_t s6_addr[16]; }; #endif /* !HAVE_STRUCT_IN6_ADDR */ #ifndef HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 { unsigned short sin6_family; uint16_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; }; #endif /* !HAVE_STRUCT_SOCKADDR_IN6 */ #ifndef AF_INET6 /* Define it to something that should never appear */ #define AF_INET6 AF_MAX #endif #ifndef PF_INET #define PF_INET AF_INET #endif #ifndef PF_INET6 #define PF_INET6 AF_INET6 #endif /* * Next, RFC2553 name / address resolution API */ #ifndef NI_NUMERICHOST # define NI_NUMERICHOST (1) #endif #ifndef NI_NAMEREQD # define NI_NAMEREQD (1<<1) #endif #ifndef NI_NUMERICSERV # define NI_NUMERICSERV (1<<2) #endif #ifndef AI_PASSIVE # define AI_PASSIVE (1) #endif #ifndef AI_CANONNAME # define AI_CANONNAME (1<<1) #endif #ifndef AI_NUMERICHOST # define AI_NUMERICHOST (1<<2) #endif #ifndef NI_MAXSERV # define NI_MAXSERV 32 #endif /* !NI_MAXSERV */ #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif /* !NI_MAXHOST */ #ifndef INT_MAX #define INT_MAX 0xffffffff #endif #ifndef EAI_NODATA # define EAI_NODATA (INT_MAX - 1) #endif #ifndef EAI_MEMORY # define EAI_MEMORY (INT_MAX - 2) #endif #ifndef EAI_NONAME # define EAI_NONAME (INT_MAX - 3) #endif #ifndef EAI_SYSTEM # define EAI_SYSTEM (INT_MAX - 4) #endif #ifndef HAVE_STRUCT_ADDRINFO struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; #endif /* !HAVE_STRUCT_ADDRINFO */ #ifndef HAVE_GETADDRINFO #ifdef getaddrinfo # undef getaddrinfo #endif #define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d)) int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); #endif /* !HAVE_GETADDRINFO */ #if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO) #define gai_strerror(a) (ssh_gai_strerror(a)) char *gai_strerror(int); #endif /* !HAVE_GAI_STRERROR */ #ifndef HAVE_FREEADDRINFO #define freeaddrinfo(a) (ssh_freeaddrinfo(a)) void freeaddrinfo(struct addrinfo *); #endif /* !HAVE_FREEADDRINFO */ #ifndef HAVE_GETNAMEINFO #define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g)) int getnameinfo(const struct sockaddr *, size_t, char *, size_t, char *, size_t, int); #endif /* !HAVE_GETNAMEINFO */ #endif /* !_FAKE_RFC2553_H */ nsd-4.1.26/compat/strptime.c0000664000175000017500000002177712416714277015355 0ustar wouterwouter/** strptime workaround (for oa macos leopard) * This strptime follows the man strptime (2001-11-12) * conforming to SUSv2, POSIX.1-2001 * * This very simple version of strptime has no: * - E alternatives * - O alternatives * - Glibc additions * - Does not process week numbers * - Does not properly processes year day * * LICENSE * Copyright (c) 2008, NLnet Labs, Matthijs Mekking. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NLnetLabs nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_CONFIG_H #include #endif #ifndef STRPTIME_WORKS #define TM_YEAR_BASE 1900 #include #include static const char *abb_weekdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; static const char *full_weekdays[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL }; static const char *abb_months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static const char *full_months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL }; static const char *ampm[] = { "am", "pm", NULL }; static int match_string(const char **buf, const char **strs) { int i = 0; for (i = 0; strs[i] != NULL; i++) { int len = strlen(strs[i]); if (strncasecmp (*buf, strs[i], len) == 0) { *buf += len; return i; } } return -1; } static int str2int(const char **buf, int max) { int ret=0, count=0; while (*buf[0] != '\0' && isdigit((unsigned char)*buf[0]) && counttm_wday = ret; break; case 'b': /* month name, abbreviated or full */ case 'B': case 'h': ret = match_string(&s, full_months); if (ret < 0) ret = match_string(&s, abb_months); if (ret < 0) { return NULL; } tm->tm_mon = ret; break; case 'c': /* date and time representation */ if (!(s = nsd_strptime(s, "%x %X", tm))) { return NULL; } break; case 'C': /* century number */ ret = str2int(&s, 2); if (ret < 0 || ret > 99) { /* must be in [00,99] */ return NULL; } if (split_year) { tm->tm_year = ret*100 + (tm->tm_year%100); } else { tm->tm_year = ret*100 - TM_YEAR_BASE; split_year = 1; } break; case 'd': /* day of month */ case 'e': ret = str2int(&s, 2); if (ret < 1 || ret > 31) { /* must be in [01,31] */ return NULL; } tm->tm_mday = ret; break; case 'D': /* equivalent to %m/%d/%y */ if (!(s = nsd_strptime(s, "%m/%d/%y", tm))) { return NULL; } break; case 'H': /* hour */ ret = str2int(&s, 2); if (ret < 0 || ret > 23) { /* must be in [00,23] */ return NULL; } tm->tm_hour = ret; break; case 'I': /* 12hr clock hour */ ret = str2int(&s, 2); if (ret < 1 || ret > 12) { /* must be in [01,12] */ return NULL; } if (ret == 12) /* actually [0,11] */ ret = 0; tm->tm_hour = ret; break; case 'j': /* day of year */ ret = str2int(&s, 2); if (ret < 1 || ret > 366) { /* must be in [001,366] */ return NULL; } tm->tm_yday = ret; break; case 'm': /* month */ ret = str2int(&s, 2); if (ret < 1 || ret > 12) { /* must be in [01,12] */ return NULL; } /* months go from 0-11 */ tm->tm_mon = (ret-1); break; case 'M': /* minute */ ret = str2int(&s, 2); if (ret < 0 || ret > 59) { /* must be in [00,59] */ return NULL; } tm->tm_min = ret; break; case 'n': /* arbitrary whitespace */ case 't': while (isspace((unsigned char)*s)) s++; break; case 'p': /* am pm */ ret = match_string(&s, ampm); if (ret < 0) { return NULL; } if (tm->tm_hour < 0 || tm->tm_hour > 11) { /* %I */ return NULL; } if (ret == 1) /* pm */ tm->tm_hour += 12; break; case 'r': /* equivalent of %I:%M:%S %p */ if (!(s = nsd_strptime(s, "%I:%M:%S %p", tm))) { return NULL; } break; case 'R': /* equivalent of %H:%M */ if (!(s = nsd_strptime(s, "%H:%M", tm))) { return NULL; } break; case 'S': /* seconds */ ret = str2int(&s, 2); /* 60 may occur for leap seconds */ /* earlier 61 was also allowed */ if (ret < 0 || ret > 60) { /* must be in [00,60] */ return NULL; } tm->tm_sec = ret; break; case 'T': /* equivalent of %H:%M:%S */ if (!(s = nsd_strptime(s, "%H:%M:%S", tm))) { return NULL; } break; case 'U': /* week number, with the first Sun of Jan being w1 */ ret = str2int(&s, 2); if (ret < 0 || ret > 53) { /* must be in [00,53] */ return NULL; } /** it is hard (and not necessary for nsd) to determine time * data from week number. **/ break; case 'w': /* day of week */ ret = str2int(&s, 1); if (ret < 0 || ret > 6) { /* must be in [0,6] */ return NULL; } tm->tm_wday = ret; break; case 'W': /* week number, with the first Mon of Jan being w1 */ ret = str2int(&s, 2); if (ret < 0 || ret > 53) { /* must be in [00,53] */ return NULL; } /** it is hard (and not necessary for nsd) to determine time * data from week number. **/ break; case 'x': /* date format */ if (!(s = nsd_strptime(s, "%m/%d/%y", tm))) { return NULL; } break; case 'X': /* time format */ if (!(s = nsd_strptime(s, "%H:%M:%S", tm))) { return NULL; } break; case 'y': /* last two digits of a year */ ret = str2int(&s, 2); if (ret < 0 || ret > 99) { /* must be in [00,99] */ return NULL; } if (split_year) { tm->tm_year = ((tm->tm_year/100) * 100) + ret; } else { split_year = 1; /** currently: * if in [0,68] we are in 21th century, * if in [69,99] we are in 20th century. **/ if (ret < 69) /* 2000 */ ret += 100; tm->tm_year = ret; } break; case 'Y': /* year */ ret = str2int(&s, 4); if (ret < 0 || ret > 9999) { return NULL; } tm->tm_year = ret - TM_YEAR_BASE; break; case '\0': default: /* unsupported, cannot match format */ return NULL; break; } } else { /* literal */ /* if input cannot match format, return NULL */ if (*s != c) return NULL; s++; } format++; } /* return pointer to remainder of s */ return (char*) s; } #endif /* STRPTIME_WORKS */ nsd-4.1.26/compat/strlcpy.c0000664000175000017500000000320510446231040015147 0ustar wouterwouter/* from openssh 4.3p2 compat/strlcpy.c */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ #include #ifndef HAVE_STRLCPY #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ nsd-4.1.26/compat/malloc.c0000664000175000017500000000060007676574217014745 0ustar wouterwouter/* Just a replacement, if the original malloc is not GNU-compliant. See autoconf documentation. */ #if HAVE_CONFIG_H #include #endif #undef malloc #include void *malloc (); /* Allocate an N-byte block of memory from the heap. If N is zero, allocate a 1-byte block. */ void * rpl_malloc (size_t n) { if (n == 0) n = 1; return malloc (n); } nsd-4.1.26/compat/reallocarray.c0000664000175000017500000000262612613664335016154 0ustar wouterwouter/* $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $ */ /* * Copyright (c) 2008 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #include #ifdef HAVE_STDINT_H #include #endif #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * reallocarray(void *optr, size_t nmemb, size_t size) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return realloc(optr, size * nmemb); } nsd-4.1.26/compat/b64_ntop.c0000664000175000017500000001641607743743014015131 0ustar wouterwouter/* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include #include #include #include #include #include #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); Assert(output[3] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } nsd-4.1.26/compat/inet_aton.c0000664000175000017500000001253012416714277015451 0ustar wouterwouter/* From openssh4.3p2 compat/inet_aton.c */ /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - * --Copyright-- */ /* OPENBSD ORIGINAL: lib/libc/net/inet_addr.c */ #include #if !defined(HAVE_INET_ATON) #include #include #include #include #include #if 0 /* * Ascii internet address interpretation routine. * The value returned is in network order. */ in_addr_t inet_addr(const char *cp) { struct in_addr val; if (inet_aton(cp, &val)) return (val.s_addr); return (INADDR_NONE); } #endif /* * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which * cannot distinguish between failure and a local broadcast address. */ int inet_aton(const char *cp, struct in_addr *addr) { uint32_t val; int base, n; char c; unsigned int parts[4]; unsigned int *pp = parts; c = *cp; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, isdigit=decimal. */ if (!isdigit((unsigned char)c)) return (0); val = 0; base = 10; if (c == '0') { c = *++cp; if (c == 'x' || c == 'X') base = 16, c = *++cp; else base = 8; } for (;;) { if (isascii((unsigned char)c) && isdigit((unsigned char)c)) { val = (val * base) + (c - '0'); c = *++cp; } else if (base == 16 && isascii((unsigned char)c) && isxdigit((unsigned char)c)) { val = (val << 4) | (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); c = *++cp; } else break; } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3) return (0); *pp++ = val; c = *++cp; } else break; } /* * Check for trailing characters. */ if (c != '\0' && (!isascii((unsigned char)c) || !isspace((unsigned char)c))) return (0); /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 0: return (0); /* initial nondigit */ case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if ((val > 0xffffff) || (parts[0] > 0xff)) return (0); val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr) addr->s_addr = htonl(val); return (1); } #endif /* !defined(HAVE_INET_ATON) */ nsd-4.1.26/compat/snprintf.c0000664000175000017500000007131012613707754015336 0ustar wouterwouter/* snprintf - compatibility implementation of snprintf, vsnprintf * * Copyright (c) 2013, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #include /* for test */ /* #define SNPRINTF_TEST 1 */ #ifdef SNPRINTF_TEST #define snprintf my_snprintf #define vsnprintf my_vsnprintf #endif /* SNPRINTF_TEST */ int snprintf(char* str, size_t size, const char* format, ...); int vsnprintf(char* str, size_t size, const char* format, va_list arg); /** * Very portable snprintf implementation, limited in functionality, * esp. for %[capital] %[nonportable] and so on. Reduced float functionality, * mostly in formatting and range (e+-16), for %f and %g. * * %s, %d, %u, %i, %x, %c, %n and %% are fully supported. * This includes width, precision, flags 0- +, and *(arg for wid,prec). * %f, %g, %m, %p have reduced support, support for wid,prec,flags,*, but * less floating point range, no %e formatting for %g. */ int snprintf(char* str, size_t size, const char* format, ...) { int r; va_list args; va_start(args, format); r = vsnprintf(str, size, format, args); va_end(args); return r; } /** add padding to string */ static void print_pad(char** at, size_t* left, int* ret, char p, int num) { while(num--) { if(*left > 1) { *(*at)++ = p; (*left)--; } (*ret)++; } } /** get negative symbol, 0 if none */ static char get_negsign(int negative, int plus, int space) { if(negative) return '-'; if(plus) return '+'; if(space) return ' '; return 0; } #define PRINT_DEC_BUFSZ 32 /* 20 is enough for 64 bit decimals */ /** print decimal into buffer, returns length */ static int print_dec(char* buf, int max, unsigned int value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print long decimal into buffer, returns length */ static int print_dec_l(char* buf, int max, unsigned long value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print long decimal into buffer, returns length */ static int print_dec_ll(char* buf, int max, unsigned long long value) { int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = '0' + value % 10; value /= 10; } return i; } /** print hex into buffer, returns length */ static int print_hex(char* buf, int max, unsigned int value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** print long hex into buffer, returns length */ static int print_hex_l(char* buf, int max, unsigned long value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** print long long hex into buffer, returns length */ static int print_hex_ll(char* buf, int max, unsigned long long value) { const char* h = "0123456789abcdef"; int i = 0; if(value == 0) { if(max > 0) { buf[0] = '0'; i = 1; } } else while(value && i < max) { buf[i++] = h[value & 0x0f]; value >>= 4; } return i; } /** copy string into result, reversed */ static void spool_str_rev(char** at, size_t* left, int* ret, const char* buf, int len) { int i = len; while(i) { if(*left > 1) { *(*at)++ = buf[--i]; (*left)--; } else --i; (*ret)++; } } /** copy string into result */ static void spool_str(char** at, size_t* left, int* ret, const char* buf, int len) { int i; for(i=0; i 1) { *(*at)++ = buf[i]; (*left)--; } (*ret)++; } } /** print number formatted */ static void print_num(char** at, size_t* left, int* ret, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space, int zero, int negative, char* buf, int len) { int w = len; /* excludes minus sign */ char s = get_negsign(negative, plus, space); if(minus) { /* left adjust the number into the field, space padding */ /* calc numw = [sign][zeroes][number] */ int numw = w; if(precision == 0 && zero) numw = 0; if(numw < precision) numw = precision; if(s) numw++; /* sign */ if(s) print_pad(at, left, ret, s, 1); /* number */ if(precision == 0 && zero) { /* "" for the number */ } else { if(w < precision) print_pad(at, left, ret, '0', precision - w); spool_str_rev(at, left, ret, buf, len); } /* spaces */ if(numw < minw) print_pad(at, left, ret, ' ', minw - numw); } else { /* pad on the left of the number */ /* calculate numw has width of [sign][zeroes][number] */ int numw = w; if(precision == 0 && zero) numw = 0; if(numw < precision) numw = precision; if(!prgiven && zeropad && numw < minw) numw = minw; else if(s) numw++; /* pad with spaces */ if(numw < minw) print_pad(at, left, ret, ' ', minw - numw); /* print sign (and one less zeropad if so) */ if(s) { print_pad(at, left, ret, s, 1); numw--; } /* pad with zeroes */ if(w < numw) print_pad(at, left, ret, '0', numw - w); if(precision == 0 && zero) return; /* print the characters for the value */ spool_str_rev(at, left, ret, buf, len); } } /** print %d and %i */ static void print_num_d(char** at, size_t* left, int* ret, int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec(buf, (int)sizeof(buf), (unsigned int)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %ld and %li */ static void print_num_ld(char** at, size_t* left, int* ret, long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec_l(buf, (int)sizeof(buf), (unsigned long)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lld and %lli */ static void print_num_lld(char** at, size_t* left, int* ret, long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = (value < 0); int zero = (value == 0); int len = print_dec_ll(buf, (int)sizeof(buf), (unsigned long long)(negative?-value:value)); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %u */ static void print_num_u(char** at, size_t* left, int* ret, unsigned int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lu */ static void print_num_lu(char** at, size_t* left, int* ret, unsigned long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec_l(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llu */ static void print_num_llu(char** at, size_t* left, int* ret, unsigned long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_dec_ll(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %x */ static void print_num_x(char** at, size_t* left, int* ret, unsigned int value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %lx */ static void print_num_lx(char** at, size_t* left, int* ret, unsigned long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex_l(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llx */ static void print_num_llx(char** at, size_t* left, int* ret, unsigned long long value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); int len = print_hex_ll(buf, (int)sizeof(buf), value); print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } /** print %llp */ static void print_num_llp(char** at, size_t* left, int* ret, void* value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_DEC_BUFSZ]; int negative = 0; int zero = (value == 0); #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX) /* avoid warning about upcast on 32bit systems */ unsigned long long llvalue = (unsigned long)value; #else unsigned long long llvalue = (unsigned long long)value; #endif int len = print_hex_ll(buf, (int)sizeof(buf), llvalue); if(zero) { buf[0]=')'; buf[1]='l'; buf[2]='i'; buf[3]='n'; buf[4]='('; len = 5; } else { /* put '0x' in front of the (reversed) buffer result */ if(len < PRINT_DEC_BUFSZ) buf[len++] = 'x'; if(len < PRINT_DEC_BUFSZ) buf[len++] = '0'; } print_num(at, left, ret, minw, precision, prgiven, zeropad, minus, plus, space, zero, negative, buf, len); } #define PRINT_FLOAT_BUFSZ 64 /* xx.yy with 20.20 about the max */ /** spool remainder after the decimal point to buffer, in reverse */ static int print_remainder(char* buf, int max, double r, int prec) { unsigned long long cap = 1; unsigned long long value; int len, i; if(prec > 19) prec = 19; /* max we can do */ if(max < prec) return 0; for(i=0; i= 5) { value++; /* that might carry to numbers before the comma, if so, * just ignore that rounding. failure because 64bitprintout */ if(value >= cap) value = cap-1; } len = print_dec_ll(buf, max, value); while(len < prec) { /* pad with zeroes, e.g. if 0.0012 */ buf[len++] = '0'; } if(len < max) buf[len++] = '.'; return len; } /** spool floating point to buffer */ static int print_float(char* buf, int max, double value, int prec) { /* as xxx.xxx if prec==0, no '.', with prec decimals after . */ /* no conversion for NAN and INF, because we do not want to require linking with -lm. */ /* Thus, the conversions use 64bit integers to convert the numbers, * which makes 19 digits before and after the decimal point the max */ unsigned long long whole = (unsigned long long)value; double remain = value - (double)whole; int len = 0; if(prec != 0) len = print_remainder(buf, max, remain, prec); len += print_dec_ll(buf+len, max-len, whole); return len; } /** print %f */ static void print_num_f(char** at, size_t* left, int* ret, double value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_FLOAT_BUFSZ]; int negative = (value < 0); int zero = 0; int len; if(!prgiven) precision = 6; len = print_float(buf, (int)sizeof(buf), negative?-value:value, precision); print_num(at, left, ret, minw, 1, 0, zeropad, minus, plus, space, zero, negative, buf, len); } /* rudimentary %g support */ static int print_float_g(char* buf, int max, double value, int prec) { unsigned long long whole = (unsigned long long)value; double remain = value - (double)whole; int before = 0; int len = 0; /* number of digits before the decimal point */ while(whole > 0) { before++; whole /= 10; } whole = (unsigned long long)value; if(prec > before && remain != 0.0) { /* see if the last decimals are zero, if so, skip them */ len = print_remainder(buf, max, remain, prec-before); while(len > 0 && buf[0]=='0') { memmove(buf, buf+1, --len); } } len += print_dec_ll(buf+len, max-len, whole); return len; } /** print %g */ static void print_num_g(char** at, size_t* left, int* ret, double value, int minw, int precision, int prgiven, int zeropad, int minus, int plus, int space) { char buf[PRINT_FLOAT_BUFSZ]; int negative = (value < 0); int zero = 0; int len; if(!prgiven) precision = 6; if(precision == 0) precision = 1; len = print_float_g(buf, (int)sizeof(buf), negative?-value:value, precision); print_num(at, left, ret, minw, 1, 0, zeropad, minus, plus, space, zero, negative, buf, len); } /** strnlen (compat implementation) */ static int my_strnlen(const char* s, int max) { int i; for(i=0; i 1) { *at++ = *fmt++; left--; } else fmt++; ret++; } /* see if we are at end */ if(!*fmt) break; /* fetch next argument % designation from format string */ fmt++; /* skip the '%' */ /********************************/ /* get the argument designation */ /********************************/ /* we must do this vararg stuff inside this function for * portability. Hence, get_designation, and print_designation * are not their own functions. */ /* printout designation: * conversion specifier: x, d, u, s, c, n, m, p * flags: # not supported * 0 zeropad (on the left) * - left adjust (right by default) * ' ' printspace for positive number (in - position). * + alwayssign * fieldwidth: [1-9][0-9]* minimum field width. * if this is * then type int next argument specifies the minwidth. * if this is negative, the - flag is set (with positive width). * precision: period[digits]*, %.2x. * if this is * then type int next argument specifies the precision. * just '.' or negative value means precision=0. * this is mindigits to print for d, i, u, x * this is aftercomma digits for f * this is max number significant digits for g * maxnumber characters to be printed for s * length: 0-none (int), 1-l (long), 2-ll (long long) * notsupported: hh (char), h (short), L (long double), q, j, z, t * Does not support %m$ and *m$ argument designation as array indices. * Does not support %#x * */ minw = 0; precision = 1; prgiven = 0; zeropad = 0; minus = 0; plus = 0; space = 0; length = 0; /* get flags in any order */ for(;;) { if(*fmt == '0') zeropad = 1; else if(*fmt == '-') minus = 1; else if(*fmt == '+') plus = 1; else if(*fmt == ' ') space = 1; else break; fmt++; } /* field width */ if(*fmt == '*') { fmt++; /* skip char */ minw = va_arg(arg, int); if(minw < 0) { minus = 1; minw = -minw; } } else while(*fmt >= '0' && *fmt <= '9') { minw = minw*10 + (*fmt++)-'0'; } /* precision */ if(*fmt == '.') { fmt++; /* skip period */ prgiven = 1; precision = 0; if(*fmt == '*') { fmt++; /* skip char */ precision = va_arg(arg, int); if(precision < 0) precision = 0; } else while(*fmt >= '0' && *fmt <= '9') { precision = precision*10 + (*fmt++)-'0'; } } /* length */ if(*fmt == 'l') { fmt++; /* skip char */ length = 1; if(*fmt == 'l') { fmt++; /* skip char */ length = 2; } } /* get the conversion */ if(!*fmt) conv = 0; else conv = *fmt++; /***********************************/ /* print that argument designation */ /***********************************/ switch(conv) { case 'i': case 'd': if(length == 0) print_num_d(&at, &left, &ret, va_arg(arg, int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_ld(&at, &left, &ret, va_arg(arg, long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_lld(&at, &left, &ret, va_arg(arg, long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'u': if(length == 0) print_num_u(&at, &left, &ret, va_arg(arg, unsigned int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_lu(&at, &left, &ret, va_arg(arg, unsigned long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_llu(&at, &left, &ret, va_arg(arg, unsigned long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'x': if(length == 0) print_num_x(&at, &left, &ret, va_arg(arg, unsigned int), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 1) print_num_lx(&at, &left, &ret, va_arg(arg, unsigned long), minw, precision, prgiven, zeropad, minus, plus, space); else if(length == 2) print_num_llx(&at, &left, &ret, va_arg(arg, unsigned long long), minw, precision, prgiven, zeropad, minus, plus, space); break; case 's': print_str(&at, &left, &ret, va_arg(arg, char*), minw, precision, prgiven, minus); break; case 'c': print_char(&at, &left, &ret, va_arg(arg, int), minw, minus); break; case 'n': *va_arg(arg, int*) = ret; break; case 'm': print_str(&at, &left, &ret, strerror(errno), minw, precision, prgiven, minus); break; case 'p': print_num_llp(&at, &left, &ret, va_arg(arg, void*), minw, precision, prgiven, zeropad, minus, plus, space); break; case '%': print_pad(&at, &left, &ret, '%', 1); break; case 'f': print_num_f(&at, &left, &ret, va_arg(arg, double), minw, precision, prgiven, zeropad, minus, plus, space); break; case 'g': print_num_g(&at, &left, &ret, va_arg(arg, double), minw, precision, prgiven, zeropad, minus, plus, space); break; /* unknown */ default: case 0: break; } } /* zero terminate */ if(left > 0) *at = 0; return ret; } #ifdef SNPRINTF_TEST /** do tests */ #undef snprintf #define DOTEST(bufsz, result, retval, ...) do { \ char buf[bufsz]; \ printf("now test %s\n", #__VA_ARGS__); \ int r=my_snprintf(buf, sizeof(buf), __VA_ARGS__); \ if(r != retval || strcmp(buf, result) != 0) { \ printf("error test(%s) was \"%s\":%d\n", \ ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ buf, r); \ exit(1); \ } \ r=snprintf(buf, sizeof(buf), __VA_ARGS__); \ if(r != retval || strcmp(buf, result) != 0) { \ printf("error test(%s) differs with system, \"%s\":%d\n", \ ""#bufsz", "#result", "#retval", "#__VA_ARGS__, \ buf, r); \ exit(1); \ } \ printf("test(\"%s\":%d) passed\n", buf, r); \ } while(0); /** test program */ int main(void) { int x = 0; /* bufsize, expectedstring, expectedretval, snprintf arguments */ DOTEST(1024, "hello", 5, "hello"); DOTEST(1024, "h", 1, "h"); /* warning from gcc for format string, but it does work * DOTEST(1024, "", 0, ""); */ DOTEST(3, "he", 5, "hello"); DOTEST(1, "", 7, "%d", 7823089); /* test positive numbers */ DOTEST(1024, "0", 1, "%d", 0); DOTEST(1024, "1", 1, "%d", 1); DOTEST(1024, "9", 1, "%d", 9); DOTEST(1024, "15", 2, "%d", 15); DOTEST(1024, "ab15cd", 6, "ab%dcd", 15); DOTEST(1024, "167", 3, "%d", 167); DOTEST(1024, "7823089", 7, "%d", 7823089); DOTEST(1024, " 12", 3, "%3d", 12); DOTEST(1024, "012", 3, "%.3d", 12); DOTEST(1024, "012", 3, "%3.3d", 12); DOTEST(1024, "012", 3, "%03d", 12); DOTEST(1024, " 012", 4, "%4.3d", 12); DOTEST(1024, "", 0, "%.0d", 0); /* test negative numbers */ DOTEST(1024, "-1", 2, "%d", -1); DOTEST(1024, "-12", 3, "%3d", -12); DOTEST(1024, " -2", 3, "%3d", -2); DOTEST(1024, "-012", 4, "%.3d", -12); DOTEST(1024, "-012", 4, "%3.3d", -12); DOTEST(1024, "-012", 4, "%4.3d", -12); DOTEST(1024, " -012", 5, "%5.3d", -12); DOTEST(1024, "-12", 3, "%03d", -12); DOTEST(1024, "-02", 3, "%03d", -2); DOTEST(1024, "-15", 3, "%d", -15); DOTEST(1024, "-7307", 5, "%d", -7307); DOTEST(1024, "-12 ", 5, "%-5d", -12); DOTEST(1024, "-00012", 6, "%-.5d", -12); /* test + and space flags */ DOTEST(1024, "+12", 3, "%+d", 12); DOTEST(1024, " 12", 3, "% d", 12); /* test %u */ DOTEST(1024, "12", 2, "%u", 12); DOTEST(1024, "0", 1, "%u", 0); DOTEST(1024, "4294967295", 10, "%u", 0xffffffff); /* test %x */ DOTEST(1024, "0", 1, "%x", 0); DOTEST(1024, "c", 1, "%x", 12); DOTEST(1024, "12ab34cd", 8, "%x", 0x12ab34cd); /* test %llu, %lld */ DOTEST(1024, "18446744073709551615", 20, "%llu", (long long)0xffffffffffffffff); DOTEST(1024, "-9223372036854775808", 20, "%lld", (long long)0x8000000000000000); DOTEST(1024, "9223372036854775808", 19, "%llu", (long long)0x8000000000000000); /* test %s */ DOTEST(1024, "hello", 5, "%s", "hello"); DOTEST(1024, " hello", 10, "%10s", "hello"); DOTEST(1024, "hello ", 10, "%-10s", "hello"); DOTEST(1024, "he", 2, "%.2s", "hello"); DOTEST(1024, " he", 4, "%4.2s", "hello"); DOTEST(1024, " h", 4, "%4.2s", "h"); /* test %c */ DOTEST(1024, "a", 1, "%c", 'a'); /* warning from gcc for format string, but it does work DOTEST(1024, " a", 5, "%5c", 'a'); DOTEST(1024, "a", 1, "%.0c", 'a'); */ /* test %n */ DOTEST(1024, "hello", 5, "hello%n", &x); if(x != 5) { printf("the %%n failed\n"); exit(1); } /* test %m */ errno = 0; DOTEST(1024, "Success", 7, "%m"); /* test %p */ DOTEST(1024, "0x10", 4, "%p", (void*)0x10); DOTEST(1024, "(nil)", 5, "%p", (void*)0x0); /* test %% */ DOTEST(1024, "%", 1, "%%"); /* test %f */ DOTEST(1024, "0.000000", 8, "%f", 0.0); DOTEST(1024, "0.00", 4, "%.2f", 0.0); /* differs, "-0.00" DOTEST(1024, "0.00", 4, "%.2f", -0.0); */ DOTEST(1024, "234.00", 6, "%.2f", 234.005); DOTEST(1024, "8973497.1246", 12, "%.4f", 8973497.12456); DOTEST(1024, "-12.000000", 10, "%f", -12.0); DOTEST(1024, "6", 1, "%.0f", 6.0); DOTEST(1024, "6", 1, "%g", 6.0); DOTEST(1024, "6.1", 3, "%g", 6.1); DOTEST(1024, "6.15", 4, "%g", 6.15); /* These format strings are from the code of NSD, Unbound, ldns */ DOTEST(1024, "abcdef", 6, "%s", "abcdef"); DOTEST(1024, "005", 3, "%03u", 5); DOTEST(1024, "12345", 5, "%03u", 12345); DOTEST(1024, "5", 1, "%d", 5); DOTEST(1024, "(nil)", 5, "%p", NULL); DOTEST(1024, "12345", 5, "%ld", (long)12345); DOTEST(1024, "12345", 5, "%lu", (long)12345); DOTEST(1024, " 12345", 12, "%12u", (unsigned)12345); DOTEST(1024, "12345", 5, "%u", (unsigned)12345); DOTEST(1024, "12345", 5, "%llu", (unsigned long long)12345); DOTEST(1024, "12345", 5, "%x", 0x12345); DOTEST(1024, "12345", 5, "%llx", (long long)0x12345); DOTEST(1024, "012345", 6, "%6.6d", 12345); DOTEST(1024, "012345", 6, "%6.6u", 12345); DOTEST(1024, "1234.54", 7, "%g", 1234.54); DOTEST(1024, "123456789.54", 12, "%.12g", 123456789.54); DOTEST(1024, "3456789123456.54", 16, "%.16g", 3456789123456.54); /* %24g does not work with 24 digits, not enough accuracy, * the first 16 digits are correct */ DOTEST(1024, "12345", 5, "%3.3d", 12345); DOTEST(1024, "000", 3, "%3.3d", 0); DOTEST(1024, "001", 3, "%3.3d", 1); DOTEST(1024, "012", 3, "%3.3d", 12); DOTEST(1024, "-012", 4, "%3.3d", -12); DOTEST(1024, "he", 2, "%.2s", "hello"); DOTEST(1024, "helloworld", 10, "%s%s", "hello", "world"); DOTEST(1024, "he", 2, "%.*s", 2, "hello"); DOTEST(1024, " hello", 7, "%*s", 7, "hello"); DOTEST(1024, "hello ", 7, "%*s", -7, "hello"); DOTEST(1024, "0", 1, "%c", '0'); DOTEST(1024, "A", 1, "%c", 'A'); DOTEST(1024, "", 1, "%c", 0); DOTEST(1024, "\010", 1, "%c", 8); DOTEST(1024, "%", 1, "%%"); DOTEST(1024, "0a", 2, "%02x", 0x0a); DOTEST(1024, "bd", 2, "%02x", 0xbd); DOTEST(1024, "12", 2, "%02ld", (long)12); DOTEST(1024, "02", 2, "%02ld", (long)2); DOTEST(1024, "02", 2, "%02u", (unsigned)2); DOTEST(1024, "765432", 6, "%05u", (unsigned)765432); DOTEST(1024, "10.234", 6, "%0.3f", 10.23421); DOTEST(1024, "123456.234", 10, "%0.3f", 123456.23421); DOTEST(1024, "123456789.234", 13, "%0.3f", 123456789.23421); DOTEST(1024, "123456.23", 9, "%.2f", 123456.23421); DOTEST(1024, "123456", 6, "%.0f", 123456.23421); DOTEST(1024, "0123", 4, "%.4x", 0x0123); DOTEST(1024, "00000123", 8, "%.8x", 0x0123); DOTEST(1024, "ffeb0cde", 8, "%.8x", 0xffeb0cde); DOTEST(1024, " 987654321", 10, "%10lu", (unsigned long)987654321); DOTEST(1024, " 987654321", 12, "%12lu", (unsigned long)987654321); DOTEST(1024, "987654321", 9, "%i", 987654321); DOTEST(1024, "-87654321", 9, "%i", -87654321); DOTEST(1024, "hello ", 16, "%-16s", "hello"); DOTEST(1024, " ", 16, "%-16s", ""); DOTEST(1024, "a ", 16, "%-16s", "a"); DOTEST(1024, "foobarfoobar ", 16, "%-16s", "foobarfoobar"); DOTEST(1024, "foobarfoobarfoobar", 18, "%-16s", "foobarfoobarfoobar"); /* combined expressions */ DOTEST(1024, "foo 1.0 size 512 edns", 21, "foo %s size %d %s%s", "1.0", 512, "", "edns"); DOTEST(15, "foo 1.0 size 5", 21, "foo %s size %d %s%s", "1.0", 512, "", "edns"); DOTEST(1024, "packet 1203ceff id", 18, "packet %2.2x%2.2x%2.2x%2.2x id", 0x12, 0x03, 0xce, 0xff); DOTEST(1024, "/tmp/testbound_123abcd.tmp", 26, "/tmp/testbound_%u%s%s.tmp", 123, "ab", "cd"); return 0; } #endif /* SNPRINTF_TEST */ nsd-4.1.26/compat/fake-rfc2553.c0000664000175000017500000001373312356721736015475 0ustar wouterwouter/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */ /* * Copyright (C) 2000-2003 Damien Miller. All rights reserved. * Copyright (C) 1999 WIDE Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Pseudo-implementation of RFC2553 name / address resolution functions * * But these functions are not implemented correctly. The minimum subset * is implemented for ssh use only. For example, this routine assumes * that ai_family is AF_INET. Don't use it for another purpose. */ #include #include #include #include #include "compat/fake-rfc2553.h" #ifndef HAVE_GETNAMEINFO int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host, size_t hostlen, char *serv, size_t servlen, int flags) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; struct hostent *hp; char tmpserv[16]; if (serv != NULL) { snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); if (strlcpy(serv, tmpserv, servlen) >= servlen) return (EAI_MEMORY); } if (host != NULL) { if (flags & NI_NUMERICHOST) { if (strlcpy(host, inet_ntoa(sin->sin_addr), hostlen) >= hostlen) return (EAI_MEMORY); else return (0); } else { hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); if (hp == NULL) return (EAI_NODATA); if (strlcpy(host, hp->h_name, hostlen) >= hostlen) return (EAI_MEMORY); else return (0); } } return (0); } #endif /* !HAVE_GETNAMEINFO */ #ifndef HAVE_GAI_STRERROR #ifdef HAVE_CONST_GAI_STRERROR_PROTO const char * #else char * #endif gai_strerror(int err) { switch (err) { case EAI_NODATA: return ("no address associated with name"); case EAI_MEMORY: return ("memory allocation failure."); case EAI_NONAME: return ("nodename nor servname provided, or not known"); default: return ("unknown/invalid error."); } } #endif /* !HAVE_GAI_STRERROR */ #ifndef HAVE_FREEADDRINFO void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next; for(; ai != NULL;) { next = ai->ai_next; free(ai); ai = next; } } #endif /* !HAVE_FREEADDRINFO */ #ifndef HAVE_GETADDRINFO static struct addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints) { struct addrinfo *ai; ai = calloc(1, sizeof(*ai) + sizeof(struct sockaddr_in)); if (ai == NULL) return (NULL); ai->ai_addr = (struct sockaddr *)(ai + 1); /* XXX -- ssh doesn't use sa_len */ ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr->sa_family = ai->ai_family = AF_INET; ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; /* XXX: the following is not generally correct, but does what we want */ if (hints->ai_socktype) ai->ai_socktype = hints->ai_socktype; else ai->ai_socktype = SOCK_STREAM; if (hints->ai_protocol) ai->ai_protocol = hints->ai_protocol; return (ai); } int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *hp; struct servent *sp; struct in_addr in; int i; long int port; u_long addr; port = 0; if (servname != NULL) { char *cp; port = strtol(servname, &cp, 10); if (port > 0 && port <= 65535 && *cp == '\0') port = htons(port); else if ((sp = getservbyname(servname, NULL)) != NULL) port = sp->s_port; else port = 0; } if (hints && hints->ai_flags & AI_PASSIVE) { addr = htonl(0x00000000); if (hostname && inet_aton(hostname, &in) != 0) addr = in.s_addr; *res = malloc_ai(port, addr, hints); if (*res == NULL) return (EAI_MEMORY); return (0); } if (!hostname) { *res = malloc_ai(port, htonl(0x7f000001), hints); if (*res == NULL) return (EAI_MEMORY); return (0); } if (inet_aton(hostname, &in)) { *res = malloc_ai(port, in.s_addr, hints); if (*res == NULL) return (EAI_MEMORY); return (0); } /* Don't try DNS if AI_NUMERICHOST is set */ if (hints && hints->ai_flags & AI_NUMERICHOST) return (EAI_NONAME); hp = gethostbyname(hostname); if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { struct addrinfo *cur, *prev; cur = prev = *res = NULL; for (i = 0; hp->h_addr_list[i]; i++) { struct in_addr *in = (struct in_addr *)hp->h_addr_list[i]; cur = malloc_ai(port, in->s_addr, hints); if (cur == NULL) { if (*res != NULL) freeaddrinfo(*res); return (EAI_MEMORY); } if (prev) prev->ai_next = cur; else *res = cur; prev = cur; } return (0); } return (EAI_NODATA); } #endif /* !HAVE_GETADDRINFO */ nsd-4.1.26/nsd-checkzone.c0000664000175000017500000000476213345735143014746 0ustar wouterwouter/* * nsd-checkzone.c -- nsd-checkzone(8) checks zones for syntax errors * * Copyright (c) 2013, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "nsd.h" #include "options.h" #include "util.h" #include "zonec.h" struct nsd nsd; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd-checkzone \n"); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } static void check_zone(struct nsd* nsd, const char* name, const char* fname) { const dname_type* dname; zone_options_type* zo; zone_type* zone; unsigned errors; /* init*/ nsd->db = namedb_open("", nsd->options); dname = dname_parse(nsd->options->region, name); if(!dname) { /* parse failure */ error("cannot parse zone name '%s'", name); } zo = zone_options_create(nsd->options->region); memset(zo, 0, sizeof(*zo)); zo->node.key = dname; zo->name = name; zone = namedb_zone_create(nsd->db, dname, zo); /* read the zone */ errors = zonec_read(name, fname, zone); if(errors > 0) { printf("zone %s file %s has %u errors\n", name, fname, errors); exit(1); } printf("zone %s is ok\n", name); namedb_close(nsd->db); } /* dummy functions to link */ int writepid(struct nsd * ATTR_UNUSED(nsd)) { return 0; } void unlinkpid(const char * ATTR_UNUSED(file)) { } void bind8_stats(struct nsd * ATTR_UNUSED(nsd)) { } void sig_handler(int ATTR_UNUSED(sig)) { } extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; struct nsd nsd; memset(&nsd, 0, sizeof(nsd)); log_init("nsd-checkzone"); /* Parse the command line... */ while ((c = getopt(argc, argv, "h")) != -1) { switch (c) { case 'h': usage(); exit(0); case '?': default: usage(); exit(1); } } argc -= optind; argv += optind; /* Commandline parse error */ if (argc != 2) { fprintf(stderr, "wrong number of arguments.\n"); usage(); exit(1); } nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); if (verbosity == 0) verbosity = nsd.options->verbosity; check_zone(&nsd, argv[0], argv[1]); region_destroy(nsd.options->region); /* yylex_destroy(); but, not available in all versions of flex */ exit(0); } nsd-4.1.26/zparser.h0000664000175000017500000001271413401455024013670 0ustar wouterwouter/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_YY_ZPARSER_H_INCLUDED # define YY_YY_ZPARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { T_A = 258, T_NS = 259, T_MX = 260, T_TXT = 261, T_CNAME = 262, T_AAAA = 263, T_PTR = 264, T_NXT = 265, T_KEY = 266, T_SOA = 267, T_SIG = 268, T_SRV = 269, T_CERT = 270, T_LOC = 271, T_MD = 272, T_MF = 273, T_MB = 274, T_MG = 275, T_MR = 276, T_NULL = 277, T_WKS = 278, T_HINFO = 279, T_MINFO = 280, T_RP = 281, T_AFSDB = 282, T_X25 = 283, T_ISDN = 284, T_RT = 285, T_NSAP = 286, T_NSAP_PTR = 287, T_PX = 288, T_GPOS = 289, T_EID = 290, T_NIMLOC = 291, T_ATMA = 292, T_NAPTR = 293, T_KX = 294, T_A6 = 295, T_DNAME = 296, T_SINK = 297, T_OPT = 298, T_APL = 299, T_UINFO = 300, T_UID = 301, T_GID = 302, T_UNSPEC = 303, T_TKEY = 304, T_TSIG = 305, T_IXFR = 306, T_AXFR = 307, T_MAILB = 308, T_MAILA = 309, T_DS = 310, T_DLV = 311, T_SSHFP = 312, T_RRSIG = 313, T_NSEC = 314, T_DNSKEY = 315, T_SPF = 316, T_NSEC3 = 317, T_IPSECKEY = 318, T_DHCID = 319, T_NSEC3PARAM = 320, T_TLSA = 321, T_URI = 322, T_NID = 323, T_L32 = 324, T_L64 = 325, T_LP = 326, T_EUI48 = 327, T_EUI64 = 328, T_CAA = 329, T_CDS = 330, T_CDNSKEY = 331, T_OPENPGPKEY = 332, T_CSYNC = 333, T_AVC = 334, T_SMIMEA = 335, DOLLAR_TTL = 336, DOLLAR_ORIGIN = 337, NL = 338, SP = 339, STR = 340, PREV = 341, BITLAB = 342, T_TTL = 343, T_RRCLASS = 344, URR = 345, T_UTYPE = 346 }; #endif /* Tokens. */ #define T_A 258 #define T_NS 259 #define T_MX 260 #define T_TXT 261 #define T_CNAME 262 #define T_AAAA 263 #define T_PTR 264 #define T_NXT 265 #define T_KEY 266 #define T_SOA 267 #define T_SIG 268 #define T_SRV 269 #define T_CERT 270 #define T_LOC 271 #define T_MD 272 #define T_MF 273 #define T_MB 274 #define T_MG 275 #define T_MR 276 #define T_NULL 277 #define T_WKS 278 #define T_HINFO 279 #define T_MINFO 280 #define T_RP 281 #define T_AFSDB 282 #define T_X25 283 #define T_ISDN 284 #define T_RT 285 #define T_NSAP 286 #define T_NSAP_PTR 287 #define T_PX 288 #define T_GPOS 289 #define T_EID 290 #define T_NIMLOC 291 #define T_ATMA 292 #define T_NAPTR 293 #define T_KX 294 #define T_A6 295 #define T_DNAME 296 #define T_SINK 297 #define T_OPT 298 #define T_APL 299 #define T_UINFO 300 #define T_UID 301 #define T_GID 302 #define T_UNSPEC 303 #define T_TKEY 304 #define T_TSIG 305 #define T_IXFR 306 #define T_AXFR 307 #define T_MAILB 308 #define T_MAILA 309 #define T_DS 310 #define T_DLV 311 #define T_SSHFP 312 #define T_RRSIG 313 #define T_NSEC 314 #define T_DNSKEY 315 #define T_SPF 316 #define T_NSEC3 317 #define T_IPSECKEY 318 #define T_DHCID 319 #define T_NSEC3PARAM 320 #define T_TLSA 321 #define T_URI 322 #define T_NID 323 #define T_L32 324 #define T_L64 325 #define T_LP 326 #define T_EUI48 327 #define T_EUI64 328 #define T_CAA 329 #define T_CDS 330 #define T_CDNSKEY 331 #define T_OPENPGPKEY 332 #define T_CSYNC 333 #define T_AVC 334 #define T_SMIMEA 335 #define DOLLAR_TTL 336 #define DOLLAR_ORIGIN 337 #define NL 338 #define SP 339 #define STR 340 #define PREV 341 #define BITLAB 342 #define T_TTL 343 #define T_RRCLASS 344 #define URR 345 #define T_UTYPE 346 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 50 "zparser.y" /* yacc.c:1909 */ domain_type *domain; const dname_type *dname; struct lex_data data; uint32_t ttl; uint16_t klass; uint16_t type; uint16_t *unknown; #line 246 "zparser.h" /* yacc.c:1909 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_ZPARSER_H_INCLUDED */ nsd-4.1.26/dbaccess.c0000664000175000017500000004437613334272434013764 0ustar wouterwouter/* * dbaccess.c -- access methods for nsd(8) database * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "dns.h" #include "namedb.h" #include "util.h" #include "options.h" #include "rdata.h" #include "udb.h" #include "udbradtree.h" #include "udbzone.h" #include "zonec.h" #include "nsec3.h" #include "difffile.h" #include "nsd.h" static time_t udb_time = 0; static unsigned long udb_rrsets = 0; static unsigned long udb_rrset_count = 0; void namedb_close(struct namedb* db) { if(db) { if(db->udb) { udb_base_close(db->udb); udb_base_free(db->udb); db->udb = NULL; } zonec_desetup_parser(); region_destroy(db->region); } } void namedb_close_udb(struct namedb* db) { if(db) { /* we cannot actually munmap the data, because other * processes still need to access the udb, so cleanup the * udb */ udb_base_free_keep_mmap(db->udb); db->udb = NULL; } } void apex_rrset_checks(namedb_type* db, rrset_type* rrset, domain_type* domain) { uint32_t soa_minimum; unsigned i; zone_type* zone = rrset->zone; assert(domain == zone->apex); (void)domain; if (rrset_rrtype(rrset) == TYPE_SOA) { zone->soa_rrset = rrset; /* BUG #103 add another soa with a tweaked ttl */ if(zone->soa_nx_rrset == 0) { zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); zone->soa_nx_rrset->rr_count = 1; zone->soa_nx_rrset->next = 0; zone->soa_nx_rrset->zone = zone; zone->soa_nx_rrset->rrs = region_alloc(db->region, sizeof(rr_type)); } memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); /* check the ttl and MINIMUM value and set accordingly */ memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), rdata_atom_size(rrset->rrs->rdatas[6])); if (rrset->rrs->ttl > ntohl(soa_minimum)) { zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); } } else if (rrset_rrtype(rrset) == TYPE_NS) { zone->ns_rrset = rrset; } else if (rrset_rrtype(rrset) == TYPE_RRSIG) { for (i = 0; i < rrset->rr_count; ++i) { if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY){ zone->is_secure = 1; break; } } } } /** read rr */ static void read_rr(namedb_type* db, rr_type* rr, udb_ptr* urr, domain_type* domain) { buffer_type buffer; ssize_t c; assert(udb_ptr_get_type(urr) == udb_chunk_type_rr); rr->owner = domain; rr->type = RR(urr)->type; rr->klass = RR(urr)->klass; rr->ttl = RR(urr)->ttl; buffer_create_from(&buffer, RR(urr)->wire, RR(urr)->len); c = rdata_wireformat_to_rdata_atoms(db->region, db->domains, rr->type, RR(urr)->len, &buffer, &rr->rdatas); if(c == -1) { /* safe on error */ rr->rdata_count = 0; rr->rdatas = NULL; return; } rr->rdata_count = c; } /** calculate rr count */ static uint16_t calculate_rr_count(udb_base* udb, udb_ptr* rrset) { udb_ptr rr; uint16_t num = 0; udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); while(rr.data) { num++; udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); } udb_ptr_unlink(&rr, udb); return num; } /** read rrset */ static void read_rrset(udb_base* udb, namedb_type* db, zone_type* zone, domain_type* domain, udb_ptr* urrset) { rrset_type* rrset; udb_ptr urr; unsigned i; assert(udb_ptr_get_type(urrset) == udb_chunk_type_rrset); /* if no RRs, do not create anything (robust) */ if(RRSET(urrset)->rrs.data == 0) return; rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); rrset->zone = zone; rrset->rr_count = calculate_rr_count(udb, urrset); rrset->rrs = (rr_type *) region_alloc_array( db->region, rrset->rr_count, sizeof(rr_type)); /* add the RRs */ udb_ptr_new(&urr, udb, &RRSET(urrset)->rrs); for(i=0; irr_count; i++) { read_rr(db, &rrset->rrs[i], &urr, domain); udb_ptr_set_rptr(&urr, udb, &RR(&urr)->next); } udb_ptr_unlink(&urr, udb); domain_add_rrset(domain, rrset); if(domain == zone->apex) apex_rrset_checks(db, rrset, domain); } /** read one elem from db, of type domain_d */ static void read_node_elem(udb_base* udb, namedb_type* db, region_type* dname_region, zone_type* zone, struct domain_d* d) { const dname_type* dname; domain_type* domain; udb_ptr urrset; dname = dname_make(dname_region, d->name, 0); if(!dname) return; domain = domain_table_insert(db->domains, dname); assert(domain); /* domain_table_insert should always return non-NULL */ /* add rrsets */ udb_ptr_init(&urrset, udb); udb_ptr_set_rptr(&urrset, udb, &d->rrsets); while(urrset.data) { read_rrset(udb, db, zone, domain, &urrset); udb_ptr_set_rptr(&urrset, udb, &RRSET(&urrset)->next); if(++udb_rrsets % ZONEC_PCT_COUNT == 0 && time(NULL) > udb_time + ZONEC_PCT_TIME) { udb_time = time(NULL); VERBOSITY(1, (LOG_INFO, "read %s %d %%", zone->opts->name, (int)(udb_rrsets*((unsigned long)100)/udb_rrset_count))); } } region_free_all(dname_region); udb_ptr_unlink(&urrset, udb); } /** recurse read radix from disk. This radix tree is by domain name, so max of * 256 depth, and thus the stack usage is small. */ static void read_zone_recurse(udb_base* udb, namedb_type* db, region_type* dname_region, zone_type* zone, struct udb_radnode_d* node) { if(node->elem.data) { /* pre-order process of node->elem, for radix tree this is * also in-order processing (identical to order tree_next()) */ read_node_elem(udb, db, dname_region, zone, (struct domain_d*) (udb->base + node->elem.data)); } if(node->lookup.data) { uint16_t i; struct udb_radarray_d* a = (struct udb_radarray_d*) (udb->base + node->lookup.data); /* we do not care for what the exact radix key is, we want * to add all of them and the read routine does not need * the radix-key, it has it stored */ for(i=0; ilen; i++) { if(a->array[i].node.data) { read_zone_recurse(udb, db, dname_region, zone, (struct udb_radnode_d*)(udb->base + a->array[i].node.data)); } } } } /** read zone data */ static void read_zone_data(udb_base* udb, namedb_type* db, region_type* dname_region, udb_ptr* z, zone_type* zone) { udb_ptr dtree; /* recursively read domains, we only read so ptrs stay valid */ udb_ptr_new(&dtree, udb, &ZONE(z)->domains); if(RADTREE(&dtree)->root.data) read_zone_recurse(udb, db, dname_region, zone, (struct udb_radnode_d*) (udb->base + RADTREE(&dtree)->root.data)); udb_ptr_unlink(&dtree, udb); } /** create a zone */ zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zo) { zone_type* zone = (zone_type *) region_alloc(db->region, sizeof(zone_type)); zone->node = radname_insert(db->zonetree, dname_name(dname), dname->name_size, zone); assert(zone->node); zone->apex = domain_table_insert(db->domains, dname); zone->apex->usage++; /* the zone.apex reference */ zone->apex->is_apex = 1; zone->soa_rrset = NULL; zone->soa_nx_rrset = NULL; zone->ns_rrset = NULL; #ifdef NSEC3 zone->nsec3_param = NULL; zone->nsec3_last = NULL; zone->nsec3tree = NULL; zone->hashtree = NULL; zone->wchashtree = NULL; zone->dshashtree = NULL; #endif zone->opts = zo; zone->filename = NULL; zone->logstr = NULL; zone->mtime.tv_sec = 0; zone->mtime.tv_nsec = 0; zone->zonestatid = 0; zone->is_secure = 0; zone->is_changed = 0; zone->is_ok = 1; return zone; } void namedb_zone_delete(namedb_type* db, zone_type* zone) { /* RRs and UDB and NSEC3 and so on must be already deleted */ radix_delete(db->zonetree, zone->node); /* see if apex can be deleted */ if(zone->apex) { zone->apex->usage --; zone->apex->is_apex = 0; if(zone->apex->usage == 0) { /* delete the apex, possibly */ domain_table_deldomain(db, zone->apex); } } /* soa_rrset is freed when the SOA was deleted */ if(zone->soa_nx_rrset) { region_recycle(db->region, zone->soa_nx_rrset->rrs, sizeof(rr_type)); region_recycle(db->region, zone->soa_nx_rrset, sizeof(rrset_type)); } #ifdef NSEC3 hash_tree_delete(db->region, zone->nsec3tree); hash_tree_delete(db->region, zone->hashtree); hash_tree_delete(db->region, zone->wchashtree); hash_tree_delete(db->region, zone->dshashtree); #endif if(zone->filename) region_recycle(db->region, zone->filename, strlen(zone->filename)+1); if(zone->logstr) region_recycle(db->region, zone->logstr, strlen(zone->logstr)+1); region_recycle(db->region, zone, sizeof(zone_type)); } #ifdef HAVE_MMAP /** read a zone */ static void read_zone(udb_base* udb, namedb_type* db, struct nsd_options* opt, region_type* dname_region, udb_ptr* z) { /* construct dname */ const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0); struct zone_options* zo = dname?zone_options_find(opt, dname):NULL; zone_type* zone; if(!dname) return; if(!zo) { /* deleted from the options, remove it from the nsd.db too */ VERBOSITY(2, (LOG_WARNING, "zone %s is deleted", dname_to_string(dname, NULL))); udb_zone_delete(udb, z); region_free_all(dname_region); return; } assert(udb_ptr_get_type(z) == udb_chunk_type_zone); udb_rrsets = 0; udb_rrset_count = ZONE(z)->rrset_count; zone = namedb_zone_create(db, dname, zo); region_free_all(dname_region); read_zone_data(udb, db, dname_region, z, zone); zone->is_changed = (ZONE(z)->is_changed != 0); #ifdef NSEC3 prehash_zone_complete(db, zone); #endif } #endif /* HAVE_MMAP */ #ifdef HAVE_MMAP /** read zones from nsd.db */ static void read_zones(udb_base* udb, namedb_type* db, struct nsd_options* opt, region_type* dname_region) { udb_ptr ztree, n, z; udb_ptr_init(&z, udb); udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); udb_radix_first(udb,&ztree,&n); udb_time = time(NULL); while(n.data) { udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem); udb_radix_next(udb, &n); /* store in case n is deleted */ read_zone(udb, db, opt, dname_region, &z); udb_ptr_zero(&z, udb); if(nsd.signal_hint_shutdown) break; } udb_ptr_unlink(&ztree, udb); udb_ptr_unlink(&n, udb); udb_ptr_unlink(&z, udb); } #endif /* HAVE_MMAP */ #ifdef HAVE_MMAP /** try to read the udb file or fail */ static int try_read_udb(namedb_type* db, int fd, const char* filename, struct nsd_options* opt) { /* * Temporary region used while loading domain names from the * database. The region is freed after each time a dname is * read from the database. */ region_type* dname_region; assert(fd != -1); if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc, NULL))) { /* fd is closed by failed udb create call */ VERBOSITY(1, (LOG_WARNING, "can not use %s, " "will create anew", filename)); return 0; } /* sanity check if can be opened */ if(udb_base_get_userflags(db->udb) != 0) { log_msg(LOG_WARNING, "%s was not closed properly, it might " "be corrupted, will create anew", filename); udb_base_free(db->udb); db->udb = NULL; return 0; } /* read if it can be opened */ dname_region = region_create(xalloc, free); /* this operation does not fail, we end up with * something, even if that is an empty namedb */ read_zones(db->udb, db, opt, dname_region); region_destroy(dname_region); return 1; } #endif /* HAVE_MMAP */ struct namedb * namedb_open (const char* filename, struct nsd_options* opt) { namedb_type* db; /* * Region used to store the loaded database. The region is * freed in namedb_close. */ region_type* db_region; int fd; #ifdef USE_MMAP_ALLOC db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1); #else /* !USE_MMAP_ALLOC */ db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); #endif /* !USE_MMAP_ALLOC */ db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb)); db->region = db_region; db->domains = domain_table_create(db->region); db->zonetree = radix_tree_create(db->region); db->diff_skip = 0; db->diff_pos = 0; zonec_setup_parser(db); if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { log_msg(LOG_ERR, "unable to load %s: cannot initialize" "timestamp", filename); region_destroy(db_region); return NULL; } /* in dbless mode there is no file to read or mmap */ if(filename == NULL || filename[0] == 0) { db->udb = NULL; return db; } #ifndef HAVE_MMAP /* no mmap() system call, use dbless mode */ VERBOSITY(1, (LOG_INFO, "no mmap(), ignoring database %s", filename)); db->udb = NULL; (void)fd; (void)opt; return db; #else /* HAVE_MMAP */ /* attempt to open, if does not exist, create a new one */ fd = open(filename, O_RDWR); if(fd == -1) { if(errno != ENOENT) { log_msg(LOG_ERR, "%s: %s", filename, strerror(errno)); region_destroy(db_region); return NULL; } } /* attempt to read the file (if it exists) */ if(fd != -1) { if(!try_read_udb(db, fd, filename, opt)) fd = -1; } /* attempt to create the file (if necessary or failed read) */ if(fd == -1) { if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc, NULL))) { region_destroy(db_region); return NULL; } if(!udb_dns_init_file(db->udb)) { region_destroy(db->region); return NULL; } } return db; #endif /* HAVE_MMAP */ } /** the the file mtime stat (or nonexist or error) */ int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist) { struct stat s; if(stat(file, &s) != 0) { mtime->tv_sec = 0; mtime->tv_nsec = 0; *nonexist = (errno == ENOENT); return 0; } *nonexist = 0; mtime->tv_sec = s.st_mtime; #ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC mtime->tv_nsec = s.st_mtimensec; #elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) mtime->tv_nsec = s.st_mtim.tv_nsec; #else mtime->tv_nsec = 0; #endif return 1; } void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, udb_ptr* last_task) { struct timespec mtime; int nonexist = 0; unsigned int errors; const char* fname; if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile) return; mtime.tv_sec = 0; mtime.tv_nsec = 0; fname = config_make_zonefile(zone->opts, nsd); if(!file_get_mtime(fname, &mtime, &nonexist)) { if(nonexist) { VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist", fname)); } else log_msg(LOG_ERR, "zonefile %s: %s", fname, strerror(errno)); if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); return; } else { const char* zone_fname = zone->filename; struct timespec zone_mtime = zone->mtime; if(nsd->db->udb) { zone_fname = udb_zone_get_file_str(nsd->db->udb, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size); udb_zone_get_mtime(nsd->db->udb, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size, &zone_mtime); } /* if no zone_fname, then it was acquired in zone transfer, * see if the file is newer than the zone transfer * (regardless if this is a different file), because the * zone transfer is a different content source too */ if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) { VERBOSITY(3, (LOG_INFO, "zonefile %s is older than " "zone transfer in memory", fname)); return; /* if zone_fname, then the file was acquired from reading it, * and see if filename changed or mtime newer to read it */ } else if(zone_fname && fname && strcmp(zone_fname, fname) == 0 && timespec_compare(&zone_mtime, &mtime) == 0) { VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified", fname)); return; } } assert(parser); /* wipe zone from memory */ #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); errors = zonec_read(zone->opts->name, fname, zone); if(errors > 0) { log_msg(LOG_ERR, "zone %s file %s read with %u errors", zone->opts->name, fname, errors); /* wipe (partial) zone from memory */ zone->is_ok = 1; #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); if(nsd->db->udb) { region_type* dname_region; udb_ptr z; /* see if we can revert to the udb stored version */ if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size)) { /* tell that zone contents has been lost */ if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); return; } /* read from udb */ dname_region = region_create(xalloc, free); udb_rrsets = 0; udb_rrset_count = ZONE(&z)->rrset_count; udb_time = time(NULL); read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone); region_destroy(dname_region); udb_ptr_unlink(&z, nsd->db->udb); } else { if(zone->filename) region_recycle(nsd->db->region, zone->filename, strlen(zone->filename)+1); zone->filename = NULL; if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; } } else { VERBOSITY(1, (LOG_INFO, "zone %s read with success", zone->opts->name)); zone->is_ok = 1; zone->is_changed = 0; /* store zone into udb */ if(nsd->db->udb) { if(!write_zone_to_udb(nsd->db->udb, zone, &mtime, fname)) { log_msg(LOG_ERR, "failed to store zone in db"); } else { VERBOSITY(2, (LOG_INFO, "zone %s written to db", zone->opts->name)); } } else { zone->mtime = mtime; if(zone->filename) region_recycle(nsd->db->region, zone->filename, strlen(zone->filename)+1); zone->filename = region_strdup(nsd->db->region, fname); if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; } } if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); #ifdef NSEC3 prehash_zone_complete(nsd->db, zone); #endif } void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task, struct zone_options* zopt) { zone_type* zone; const dname_type* dname = (const dname_type*)zopt->node.key; /* find zone to go with it, or create it */ zone = namedb_find_zone(nsd->db, dname); if(!zone) { zone = namedb_zone_create(nsd->db, dname, zopt); } namedb_read_zonefile(nsd, zone, taskudb, last_task); } void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task) { struct zone_options* zo; /* check all zones in opt, create if not exist in main db */ RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { namedb_check_zonefile(nsd, taskudb, last_task, zo); if(nsd->signal_hint_shutdown) break; } } nsd-4.1.26/dbcreate.c0000664000175000017500000002602713272617055013762 0ustar wouterwouter/* * dbcreate.c -- routines to create an nsd(8) name database * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "namedb.h" #include "udb.h" #include "udbradtree.h" #include "udbzone.h" #include "options.h" #include "nsd.h" /* pathname directory separator character */ #define PATHSEP '/' /** add an rdata (uncompressed) to the destination */ static size_t add_rdata(rr_type* rr, unsigned i, uint8_t* buf, size_t buflen) { switch(rdata_atom_wireformat_type(rr->type, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: { const dname_type* dname = domain_dname( rdata_atom_domain(rr->rdatas[i])); if(dname->name_size > buflen) return 0; memmove(buf, dname_name(dname), dname->name_size); return dname->name_size; } default: break; } if(rdata_atom_size(rr->rdatas[i]) > buflen) return 0; memmove(buf, rdata_atom_data(rr->rdatas[i]), rdata_atom_size(rr->rdatas[i])); return rdata_atom_size(rr->rdatas[i]); } /* marshal rdata into buffer, must be MAX_RDLENGTH in size */ size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz) { size_t len = 0; unsigned i; assert(rr); for(i=0; irdata_count; i++) { len += add_rdata(rr, i, rdata+len, sz-len); } return len; } /** delete an RR */ void udb_del_rr(udb_base* udb, udb_ptr* z, rr_type* rr) { /* marshal the rdata (uncompressed) into a buffer */ uint8_t rdata[MAX_RDLENGTH]; size_t rdatalen = rr_marshal_rdata(rr, rdata, sizeof(rdata)); assert(udb); udb_zone_del_rr(udb, z, dname_name(domain_dname(rr->owner)), domain_dname(rr->owner)->name_size, rr->type, rr->klass, rdata, rdatalen); } /** write rr */ int udb_write_rr(udb_base* udb, udb_ptr* z, rr_type* rr) { /* marshal the rdata (uncompressed) into a buffer */ uint8_t rdata[MAX_RDLENGTH]; size_t rdatalen = 0; unsigned i; assert(rr); for(i=0; irdata_count; i++) { rdatalen += add_rdata(rr, i, rdata+rdatalen, sizeof(rdata)-rdatalen); } assert(udb); return udb_zone_add_rr(udb, z, dname_name(domain_dname(rr->owner)), domain_dname(rr->owner)->name_size, rr->type, rr->klass, rr->ttl, rdata, rdatalen); } /** write rrset */ static int write_rrset(udb_base* udb, udb_ptr* z, rrset_type* rrset) { unsigned i; for(i=0; irr_count; i++) { if(!udb_write_rr(udb, z, &rrset->rrs[i])) return 0; } return 1; } /** write a zone */ static int write_zone(udb_base* udb, udb_ptr* z, zone_type* zone) { /* write all domains in the zone */ domain_type* walk; rrset_type* rrset; unsigned long n = 0, c = 0; time_t t = time(NULL); /* count domains: for pct logging */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk=domain_next(walk)) { n++; } /* write them */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk=domain_next(walk)) { /* write all rrsets (in the zone) for this domain */ for(rrset=walk->rrsets; rrset; rrset=rrset->next) { if(rrset->zone == zone) { if(!write_rrset(udb, z, rrset)) return 0; } } /* only check every ... domains, and print pct */ if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > t + ZONEC_PCT_TIME) { t = time(NULL); VERBOSITY(1, (LOG_INFO, "write %s %d %%", zone->opts->name, (int)(c*((unsigned long)100)/n))); } } return 1; } /** create and write a zone */ int write_zone_to_udb(udb_base* udb, zone_type* zone, struct timespec* mtime, const char* file_str) { udb_ptr z; /* make udb dirty */ udb_base_set_userflags(udb, 1); /* find or create zone */ if(udb_zone_search(udb, &z, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size)) { /* wipe existing contents */ udb_zone_clear(udb, &z); } else { if(!udb_zone_create(udb, &z, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size)) { udb_base_set_userflags(udb, 0); return 0; } } /* set mtime */ ZONE(&z)->mtime = (uint64_t)mtime->tv_sec; ZONE(&z)->mtime_nsec = (uint64_t)mtime->tv_nsec; ZONE(&z)->is_changed = 0; udb_zone_set_log_str(udb, &z, NULL); udb_zone_set_file_str(udb, &z, file_str); /* write zone */ if(!write_zone(udb, &z, zone)) { udb_base_set_userflags(udb, 0); return 0; } udb_ptr_unlink(&z, udb); udb_base_set_userflags(udb, 0); return 1; } static int print_rrs(FILE* out, struct zone* zone) { rrset_type *rrset; domain_type *domain = zone->apex; region_type* region = region_create(xalloc, free); region_type* rr_region = region_create(xalloc, free); buffer_type* rr_buffer = buffer_create(region, MAX_RDLENGTH); struct state_pretty_rr* state = create_pretty_rr(region); /* first print the SOA record for the zone */ if(zone->soa_rrset) { size_t i; for(i=0; i < zone->soa_rrset->rr_count; i++) { if(!print_rr(out, state, &zone->soa_rrset->rrs[i], rr_region, rr_buffer)){ log_msg(LOG_ERR, "There was an error " "printing SOARR to zone %s", zone->opts->name); region_destroy(region); region_destroy(rr_region); return 0; } } } /* go through entire tree below the zone apex (incl subzones) */ while(domain && domain_is_subdomain(domain, zone->apex)) { for(rrset = domain->rrsets; rrset; rrset=rrset->next) { size_t i; if(rrset->zone != zone || rrset == zone->soa_rrset) continue; for(i=0; i < rrset->rr_count; i++) { if(!print_rr(out, state, &rrset->rrs[i], rr_region, rr_buffer)){ log_msg(LOG_ERR, "There was an error " "printing RR to zone %s", zone->opts->name); region_destroy(region); region_destroy(rr_region); return 0; } } } domain = domain_next(domain); } region_destroy(region); region_destroy(rr_region); return 1; } static int print_header(zone_type* zone, FILE* out, time_t* now, const char* logs) { char buf[4096+16]; /* ctime prints newline at end of this line */ snprintf(buf, sizeof(buf), "; zone %s written by NSD %s on %s", zone->opts->name, PACKAGE_VERSION, ctime(now)); if(!write_data(out, buf, strlen(buf))) return 0; if(!logs || logs[0] == 0) return 1; snprintf(buf, sizeof(buf), "; %s\n", logs); return write_data(out, buf, strlen(buf)); } static int write_to_zonefile(zone_type* zone, const char* filename, const char* logs) { time_t now = time(0); FILE *out = fopen(filename, "w"); if(!out) { log_msg(LOG_ERR, "cannot write zone %s file %s: %s", zone->opts->name, filename, strerror(errno)); return 0; } if(!print_header(zone, out, &now, logs)) { fclose(out); log_msg(LOG_ERR, "There was an error printing " "the header to zone %s", zone->opts->name); return 0; } if(!print_rrs(out, zone)) { fclose(out); return 0; } if(fclose(out) != 0) { log_msg(LOG_ERR, "cannot write zone %s to file %s: fclose: %s", zone->opts->name, filename, strerror(errno)); return 0; } return 1; } /** create directories above this file, .../dir/dir/dir/file */ int create_dirs(const char* path) { char dir[4096]; char* p; strlcpy(dir, path, sizeof(dir)); /* if we start with / then do not try to create '' */ if(dir[0] == PATHSEP) p = strchr(dir+1, PATHSEP); else p = strchr(dir, PATHSEP); /* create each directory component from the left */ while(p) { assert(*p == PATHSEP); *p = 0; /* end the directory name here */ if(mkdir(dir #ifndef MKDIR_HAS_ONE_ARG , 0750 #endif ) == -1) { if(errno != EEXIST) { log_msg(LOG_ERR, "create dir %s: %s", dir, strerror(errno)); return 0; } /* it already exists, OK, continue */ } *p = PATHSEP; p = strchr(p+1, PATHSEP); } return 1; } /** create pathname components and check if file exists */ static int create_path_components(const char* path, int* notexist) { /* stat the file, to see if it exists, and if its directories exist */ struct stat s; if(stat(path, &s) != 0) { if(errno == ENOENT) { *notexist = 1; /* see if we need to create pathname components */ return create_dirs(path); } log_msg(LOG_ERR, "cannot stat %s: %s", path, strerror(errno)); return 0; } *notexist = 0; return 1; } void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt) { const char* zfile; int notexist = 0; zone_type* zone; /* if no zone exists, it has no contents or it has no zonefile * configured, then no need to write data to disk */ if(!zopt->pattern->zonefile) return; zone = namedb_find_zone(nsd->db, (const dname_type*)zopt->node.key); if(!zone || !zone->apex || !zone->soa_rrset) return; /* write if file does not exist, or if changed */ /* so, determine filename, create directory components, check exist*/ zfile = config_make_zonefile(zopt, nsd); if(!create_path_components(zfile, ¬exist)) { log_msg(LOG_ERR, "could not write zone %s to file %s because " "the path could not be created", zopt->name, zfile); return; } /* if not changed, do not write. */ if(notexist || zone->is_changed) { char logs[4096]; char bakfile[4096]; struct timespec mtime; udb_ptr zudb; if(nsd->db->udb) { if(!udb_zone_search(nsd->db->udb, &zudb, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size)) return; /* zone does not exist in db */ } /* write to zfile~ first, then rename if that works */ snprintf(bakfile, sizeof(bakfile), "%s~", zfile); if(nsd->db->udb && ZONE(&zudb)->log_str.data) { udb_ptr s; udb_ptr_new(&s, nsd->db->udb, &ZONE(&zudb)->log_str); strlcpy(logs, (char*)udb_ptr_data(&s), sizeof(logs)); udb_ptr_unlink(&s, nsd->db->udb); } else if(zone->logstr) { strlcpy(logs, zone->logstr, sizeof(logs)); } else logs[0] = 0; VERBOSITY(1, (LOG_INFO, "writing zone %s to file %s", zone->opts->name, zfile)); if(!write_to_zonefile(zone, bakfile, logs)) { if(nsd->db->udb) udb_ptr_unlink(&zudb, nsd->db->udb); (void)unlink(bakfile); /* delete failed file */ return; /* error already printed */ } if(rename(bakfile, zfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", bakfile, zfile, strerror(errno)); if(nsd->db->udb) udb_ptr_unlink(&zudb, nsd->db->udb); (void)unlink(bakfile); /* delete failed file */ return; } zone->is_changed = 0; /* fetch the mtime of the just created zonefile so we * do not waste effort reading it back in */ if(!file_get_mtime(zfile, &mtime, ¬exist)) { get_time(&mtime); } if(nsd->db->udb) { ZONE(&zudb)->mtime = (uint64_t)mtime.tv_sec; ZONE(&zudb)->mtime_nsec = (uint64_t)mtime.tv_nsec; ZONE(&zudb)->is_changed = 0; udb_zone_set_log_str(nsd->db->udb, &zudb, NULL); udb_ptr_unlink(&zudb, nsd->db->udb); } else { zone->mtime = mtime; if(zone->filename) region_recycle(nsd->db->region, zone->filename, strlen(zone->filename)+1); zone->filename = region_strdup(nsd->db->region, zfile); if(zone->logstr) region_recycle(nsd->db->region, zone->logstr, strlen(zone->logstr)+1); zone->logstr = NULL; } } } void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options) { struct zone_options* zo; RBTREE_FOR(zo, struct zone_options*, options->zone_options) { namedb_write_zonefile(nsd, zo); } } nsd-4.1.26/region-allocator.c0000664000175000017500000003320413151262166015440 0ustar wouterwouter/* * region-allocator.c -- region based memory allocator. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "region-allocator.h" #include "util.h" /** This value is enough so that x*y does not overflow if both < than this */ #define REGION_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) #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)total_allocated = 0; result->small_objects = 0; result->large_objects = 0; result->chunk_count = 1; result->unused_space = 0; result->recycle_bin = NULL; result->recycle_size = 0; result->large_list = NULL; result->allocated = 0; result->data = NULL; result->initial_data = NULL; result->allocator = allocator; result->deallocator = deallocator; assert(initial_cleanup_count > 0); result->maximum_cleanup_count = initial_cleanup_count; result->cleanup_count = 0; result->cleanups = (cleanup_type *) allocator( result->maximum_cleanup_count * sizeof(cleanup_type)); if (!result->cleanups) { deallocator(result); return NULL; } result->chunk_size = DEFAULT_CHUNK_SIZE; result->large_object_size = DEFAULT_LARGE_OBJECT_SIZE; return result; } region_type * region_create(void *(*allocator)(size_t size), void (*deallocator)(void *)) { region_type* result = alloc_region_base(allocator, deallocator, DEFAULT_INITIAL_CLEANUP_SIZE); if(!result) return NULL; result->data = (char *) allocator(result->chunk_size); if (!result->data) { deallocator(result->cleanups); deallocator(result); return NULL; } result->initial_data = result->data; return result; } region_type *region_create_custom(void *(*allocator)(size_t), void (*deallocator)(void *), size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size, int recycle) { region_type* result = alloc_region_base(allocator, deallocator, initial_cleanup_size); if(!result) return NULL; assert(large_object_size <= chunk_size); result->chunk_size = chunk_size; result->large_object_size = large_object_size; if(result->chunk_size > 0) { result->data = (char *) allocator(result->chunk_size); if (!result->data) { deallocator(result->cleanups); deallocator(result); return NULL; } result->initial_data = result->data; } if(recycle) { result->recycle_bin = allocator(sizeof(struct recycle_elem*) * result->large_object_size); if(!result->recycle_bin) { region_destroy(result); return NULL; } memset(result->recycle_bin, 0, sizeof(struct recycle_elem*) * result->large_object_size); } return result; } void region_destroy(region_type *region) { void (*deallocator)(void *); if (!region) return; deallocator = region->deallocator; region_free_all(region); deallocator(region->cleanups); deallocator(region->initial_data); if(region->recycle_bin) deallocator(region->recycle_bin); if(region->large_list) { struct large_elem* p = region->large_list, *np; while(p) { np = p->next; deallocator(p); p = np; } } deallocator(region); } size_t region_add_cleanup(region_type *region, void (*action)(void *), void *data) { assert(action); if (region->cleanup_count >= region->maximum_cleanup_count) { cleanup_type *cleanups = (cleanup_type *) region->allocator( 2 * region->maximum_cleanup_count * sizeof(cleanup_type)); if (!cleanups) return 0; memcpy(cleanups, region->cleanups, region->cleanup_count * sizeof(cleanup_type)); region->deallocator(region->cleanups); region->cleanups = cleanups; region->maximum_cleanup_count *= 2; } region->cleanups[region->cleanup_count].action = action; region->cleanups[region->cleanup_count].data = data; ++region->cleanup_count; return region->cleanup_count; } void region_remove_cleanup(region_type *region, void (*action)(void *), void *data) { size_t i; for(i=0; icleanup_count; i++) { if(region->cleanups[i].action == action && region->cleanups[i].data == data) { region->cleanup_count--; region->cleanups[i] = region->cleanups[region->cleanup_count]; return; } } } void * region_alloc(region_type *region, size_t size) { size_t aligned_size; void *result; if (size == 0) { size = 1; } aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if (aligned_size >= region->large_object_size) { result = region->allocator(size + sizeof(struct large_elem)); if (!result) return NULL; ((struct large_elem*)result)->prev = NULL; ((struct large_elem*)result)->next = region->large_list; if(region->large_list) region->large_list->prev = (struct large_elem*)result; region->large_list = (struct large_elem*)result; region->total_allocated += size; ++region->large_objects; return result + sizeof(struct large_elem); } if (region->recycle_bin && region->recycle_bin[aligned_size]) { result = (void*)region->recycle_bin[aligned_size]; region->recycle_bin[aligned_size] = region->recycle_bin[aligned_size]->next; region->recycle_size -= aligned_size; region->unused_space += aligned_size - size; return result; } if (region->allocated + aligned_size > region->chunk_size) { void *chunk = region->allocator(region->chunk_size); size_t wasted; if (!chunk) return NULL; wasted = (region->chunk_size - region->allocated) & (~(ALIGNMENT-1)); 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; region_recycle(region, region->data+region->allocated, wasted); region->allocated += wasted; } ++region->chunk_count; region->unused_space += region->chunk_size - region->allocated; if(!region_add_cleanup(region, region->deallocator, chunk)) { region->deallocator(chunk); region->chunk_count--; region->unused_space -= region->chunk_size - region->allocated; return NULL; } region->allocated = 0; region->data = (char *) chunk; } result = region->data + region->allocated; region->allocated += aligned_size; region->total_allocated += aligned_size; region->unused_space += aligned_size - size; ++region->small_objects; return result; } void * region_alloc_init(region_type *region, const void *init, size_t size) { void *result = region_alloc(region, size); if (!result) return NULL; memcpy(result, init, size); return result; } void * region_alloc_zero(region_type *region, size_t size) { void *result = region_alloc(region, size); if (!result) return NULL; memset(result, 0, size); return result; } void * region_alloc_array_init(region_type *region, const void *init, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array_init failed because of integer overflow"); exit(1); } return region_alloc_init(region, init, num*size); } void * region_alloc_array_zero(region_type *region, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array_zero failed because of integer overflow"); exit(1); } return region_alloc_zero(region, num*size); } void * region_alloc_array(region_type *region, size_t num, size_t size) { if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && num > 0 && SIZE_MAX / num < size) { log_msg(LOG_ERR, "region_alloc_array failed because of integer overflow"); exit(1); } return region_alloc(region, num*size); } void region_free_all(region_type *region) { size_t i; assert(region); assert(region->cleanups); i = region->cleanup_count; while (i > 0) { --i; assert(region->cleanups[i].action); region->cleanups[i].action(region->cleanups[i].data); } if(region->recycle_bin) { memset(region->recycle_bin, 0, sizeof(struct recycle_elem*) * region->large_object_size); region->recycle_size = 0; } if(region->large_list) { struct large_elem* p = region->large_list, *np; void (*deallocator)(void *) = region->deallocator; while(p) { np = p->next; deallocator(p); p = np; } region->large_list = NULL; } region->data = region->initial_data; region->cleanup_count = 0; region->allocated = 0; region->total_allocated = 0; region->small_objects = 0; region->large_objects = 0; region->chunk_count = 1; region->unused_space = 0; } char * region_strdup(region_type *region, const char *string) { return (char *) region_alloc_init(region, string, strlen(string) + 1); } void region_recycle(region_type *region, void *block, size_t size) { size_t aligned_size; if(!block || !region->recycle_bin) return; if (size == 0) { size = 1; } aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if(aligned_size < region->large_object_size) { struct recycle_elem* elem = (struct recycle_elem*)block; /* we rely on the fact that ALIGNMENT is void* so the next will fit */ assert(aligned_size >= sizeof(struct recycle_elem)); #ifdef CHECK_DOUBLE_FREE if(CHECK_DOUBLE_FREE) { /* make sure the same ptr is not freed twice. */ struct recycle_elem *p = region->recycle_bin[aligned_size]; while(p) { assert(p != elem); p = p->next; } } #endif elem->next = region->recycle_bin[aligned_size]; region->recycle_bin[aligned_size] = elem; region->recycle_size += aligned_size; region->unused_space -= aligned_size - size; return; } else { struct large_elem* l; /* a large allocation */ region->total_allocated -= size; --region->large_objects; l = (struct large_elem*)(block-sizeof(struct large_elem)); if(l->prev) l->prev->next = l->next; else region->large_list = l->next; if(l->next) l->next->prev = l->prev; region->deallocator(l); } } void region_dump_stats(region_type *region, FILE *out) { fprintf(out, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin", (unsigned long) (region->small_objects + region->large_objects), (unsigned long) region->small_objects, (unsigned long) region->large_objects, (unsigned long) region->total_allocated, (unsigned long) region->unused_space, (unsigned long) region->chunk_count, (unsigned long) region->cleanup_count, (unsigned long) region->recycle_size); if(1 && region->recycle_bin) { /* print details of the recycle bin */ size_t i; for(i=0; ilarge_object_size; i++) { size_t count = 0; struct recycle_elem* el = region->recycle_bin[i]; while(el) { count++; el = el->next; } if(i%ALIGNMENT == 0 && i!=0) fprintf(out, " %lu", (unsigned long)count); } } } size_t region_get_recycle_size(region_type* region) { return region->recycle_size; } size_t region_get_mem(region_type* region) { return region->total_allocated; } size_t region_get_mem_unused(region_type* region) { return region->unused_space; } /* debug routine */ void region_log_stats(region_type *region) { char buf[10240], *str=buf; int strl = sizeof(buf); int len; snprintf(str, strl, "%lu objects (%lu small/%lu large), %lu bytes allocated (%lu wasted) in %lu chunks, %lu cleanups, %lu in recyclebin", (unsigned long) (region->small_objects + region->large_objects), (unsigned long) region->small_objects, (unsigned long) region->large_objects, (unsigned long) region->total_allocated, (unsigned long) region->unused_space, (unsigned long) region->chunk_count, (unsigned long) region->cleanup_count, (unsigned long) region->recycle_size); len = strlen(str); str+=len; strl-=len; if(1 && region->recycle_bin) { /* print details of the recycle bin */ size_t i; for(i=0; ilarge_object_size; i++) { size_t count = 0; struct recycle_elem* el = region->recycle_bin[i]; while(el) { count++; el = el->next; } if(i%ALIGNMENT == 0 && i!=0) { snprintf(str, strl, " %lu", (unsigned long)count); len = strlen(str); str+=len; strl-=len; } } } log_msg(LOG_INFO, "memory: %s", buf); } nsd-4.1.26/dns.c0000664000175000017500000010540313317655232012770 0ustar wouterwouter/* * dns.c -- DNS definitions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "dns.h" #include "zonec.h" #include "zparser.h" /* Taken from RFC 1035, section 3.2.4. */ static lookup_table_type dns_rrclasses[] = { { CLASS_IN, "IN" }, /* the Internet */ { CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */ { CLASS_CH, "CH" }, /* the CHAOS class */ { CLASS_HS, "HS" }, /* Hesiod */ { 0, NULL } }; static rrtype_descriptor_type rrtype_descriptors[(RRTYPE_DESCRIPTORS_LENGTH+1)] = { /* 0 */ { 0, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 1 */ { TYPE_A, "A", T_A, 1, 1, { RDATA_WF_A }, { RDATA_ZF_A } }, /* 2 */ { TYPE_NS, "NS", T_NS, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 3 */ { TYPE_MD, "MD", T_MD, 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 4 */ { TYPE_MF, "MF", T_MF, 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 5 */ { TYPE_CNAME, "CNAME", T_CNAME, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 6 */ { TYPE_SOA, "SOA", T_SOA, 7, 7, { RDATA_WF_COMPRESSED_DNAME, RDATA_WF_COMPRESSED_DNAME, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD, RDATA_ZF_PERIOD } }, /* 7 */ { TYPE_MB, "MB", T_MB, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 8 */ { TYPE_MG, "MG", T_MG, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 9 */ { TYPE_MR, "MR", T_MR, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 10 */ { TYPE_NULL, "NULL", T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 11 */ { TYPE_WKS, "WKS", T_WKS, 2, 2, { RDATA_WF_A, RDATA_WF_BINARY }, { RDATA_ZF_A, RDATA_ZF_SERVICES } }, /* 12 */ { TYPE_PTR, "PTR", T_PTR, 1, 1, { RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 13 */ { TYPE_HINFO, "HINFO", T_HINFO, 2, 2, { RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_TEXT, RDATA_ZF_TEXT } }, /* 14 */ { TYPE_MINFO, "MINFO", T_MINFO, 2, 2, { RDATA_WF_COMPRESSED_DNAME, RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 15 */ { TYPE_MX, "MX", T_MX, 2, 2, { RDATA_WF_SHORT, RDATA_WF_COMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 16 */ { TYPE_TXT, "TXT", T_TXT, 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 17 */ { TYPE_RP, "RP", T_RP, 2, 2, { RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 18 */ { TYPE_AFSDB, "AFSDB", T_AFSDB, 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 19 */ { TYPE_X25, "X25", T_X25, 1, 1, { RDATA_WF_TEXT }, { RDATA_ZF_TEXT } }, /* 20 */ { TYPE_ISDN, "ISDN", T_ISDN, 1, 2, { RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_TEXT, RDATA_ZF_TEXT } }, /* 21 */ { TYPE_RT, "RT", T_RT, 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 22 */ { TYPE_NSAP, "NSAP", T_NSAP, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_NSAP } }, /* 23 */ { 23, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 24 */ { TYPE_SIG, "SIG", T_SIG, 9, 9, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_RRTYPE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_PERIOD, RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_DNAME, RDATA_ZF_BASE64 } }, /* 25 */ { TYPE_KEY, "KEY", T_KEY, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 26 */ { TYPE_PX, "PX", T_PX, 3, 3, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME, RDATA_ZF_DNAME } }, /* 27 */ { 27, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 28 */ { TYPE_AAAA, "AAAA", T_AAAA, 1, 1, { RDATA_WF_AAAA }, { RDATA_ZF_AAAA } }, /* 29 */ { TYPE_LOC, "LOC", T_LOC, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_LOC } }, /* 30 */ { TYPE_NXT, "NXT", T_NXT, 2, 2, { RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_DNAME, RDATA_ZF_NXT } }, /* 31 */ { 31, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 32 */ { 32, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 33 */ { TYPE_SRV, "SRV", T_SRV, 4, 4, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 34 */ { 34, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 35 */ { TYPE_NAPTR, "NAPTR", T_NAPTR, 6, 6, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_DNAME } }, /* 36 */ { TYPE_KX, "KX", T_KX, 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 37 */ { TYPE_CERT, "CERT", T_CERT, 4, 4, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_CERTIFICATE_TYPE, RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 38 */ { TYPE_A6, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 39 */ { TYPE_DNAME, "DNAME", T_DNAME, 1, 1, { RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_DNAME } }, /* 40 */ { 40, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 41 */ { TYPE_OPT, "OPT", T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 42 */ { TYPE_APL, "APL", T_APL, 0, MAXRDATALEN, { RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL, RDATA_WF_APL }, { RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL, RDATA_ZF_APL } }, /* 43 */ { TYPE_DS, "DS", T_DS, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 44 */ { TYPE_SSHFP, "SSHFP", T_SSHFP, 3, 3, { RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 45 */ { TYPE_IPSECKEY, "IPSECKEY", T_IPSECKEY, 4, 5, { RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_IPSECGATEWAY, RDATA_WF_BINARY }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_IPSECGATEWAY, RDATA_ZF_BASE64 } }, /* 46 */ { TYPE_RRSIG, "RRSIG", T_RRSIG, 9, 9, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_RRTYPE, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_PERIOD, RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_LITERAL_DNAME, RDATA_ZF_BASE64 } }, /* 47 */ { TYPE_NSEC, "NSEC", T_NSEC, 2, 2, { RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY }, { RDATA_ZF_LITERAL_DNAME, RDATA_ZF_NSEC } }, /* 48 */ { TYPE_DNSKEY, "DNSKEY", T_DNSKEY, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 49 */ { TYPE_DHCID, "DHCID", T_DHCID, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_BASE64 } }, /* 50 */ { TYPE_NSEC3, "NSEC3", T_NSEC3, 6, 6, { RDATA_WF_BYTE, /* hash type */ RDATA_WF_BYTE, /* flags */ RDATA_WF_SHORT, /* iterations */ RDATA_WF_BINARYWITHLENGTH, /* salt */ RDATA_WF_BINARYWITHLENGTH, /* next hashed name */ RDATA_WF_BINARY /* type bitmap */ }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_SHORT, RDATA_ZF_HEX_LEN, RDATA_ZF_BASE32, RDATA_ZF_NSEC } }, /* 51 */ { TYPE_NSEC3PARAM, "NSEC3PARAM", T_NSEC3PARAM, 4, 4, { RDATA_WF_BYTE, /* hash type */ RDATA_WF_BYTE, /* flags */ RDATA_WF_SHORT, /* iterations */ RDATA_WF_BINARYWITHLENGTH /* salt */ }, { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_SHORT, RDATA_ZF_HEX_LEN } }, /* 52 */ { TYPE_TLSA, "TLSA", T_TLSA, 4, 4, { RDATA_WF_BYTE, /* usage */ RDATA_WF_BYTE, /* selector */ RDATA_WF_BYTE, /* matching type */ RDATA_WF_BINARY }, /* certificate association data */ { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 53 */ { TYPE_SMIMEA, "SMIMEA", T_SMIMEA, 4, 4, { RDATA_WF_BYTE, /* usage */ RDATA_WF_BYTE, /* selector */ RDATA_WF_BYTE, /* matching type */ RDATA_WF_BINARY }, /* certificate association data */ { RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 54 */ { 54, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 55 - HIP [RFC 5205] */ { 55, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 56 - NINFO */ { 56, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 57 - RKEY */ { 57, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 58 - TALINK */ { 58, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 59 - CDS */ { TYPE_CDS, "CDS", T_CDS, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, /* 60 - CDNSKEY */ { TYPE_CDNSKEY, "CDNSKEY", T_CDNSKEY, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM, RDATA_ZF_BASE64 } }, /* 61 - OPENPGPKEY */ { TYPE_OPENPGPKEY, "OPENPGPKEY", T_OPENPGPKEY, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_BASE64 } }, /* 62 - CSYNC */ { TYPE_CSYNC, "CSYNC", T_CSYNC, 3, 3, { RDATA_WF_LONG, RDATA_WF_SHORT, RDATA_WF_BINARY }, { RDATA_ZF_LONG, RDATA_ZF_SHORT, RDATA_ZF_NSEC } }, /* 63 */ { 63, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 64 */ { 64, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 65 */ { 65, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 66 */ { 66, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 67 */ { 67, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 68 */ { 68, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 69 */ { 69, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 70 */ { 70, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 71 */ { 71, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 72 */ { 72, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 73 */ { 73, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 74 */ { 74, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 75 */ { 75, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 76 */ { 76, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 77 */ { 77, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 78 */ { 78, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 79 */ { 79, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 80 */ { 80, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 81 */ { 81, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 82 */ { 82, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 83 */ { 83, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 84 */ { 84, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 85 */ { 85, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 86 */ { 86, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 87 */ { 87, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 88 */ { 88, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 89 */ { 89, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 90 */ { 90, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 91 */ { 91, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 92 */ { 92, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 93 */ { 93, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 94 */ { 94, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 95 */ { 95, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 96 */ { 96, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 97 */ { 97, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 98 */ { 98, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 99 */ { TYPE_SPF, "SPF", T_SPF, 1, MAXRDATALEN, { RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT, RDATA_WF_TEXT }, { RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT, RDATA_ZF_TEXT } }, /* 100 - UINFO */ { 100, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 101 - UID */ { 101, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 102 - GID */ { 102, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 103 - UNSPEC */ { 103, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 104 */ { TYPE_NID, "NID", T_NID, 2, 2, { RDATA_WF_SHORT, RDATA_WF_ILNP64 }, { RDATA_ZF_SHORT, RDATA_ZF_ILNP64 } }, /* 105 */ { TYPE_L32, "L32", T_L32, 2, 2, { RDATA_WF_SHORT, RDATA_WF_A }, { RDATA_ZF_SHORT, RDATA_ZF_A } }, /* 106 */ { TYPE_L64, "L64", T_L64, 2, 2, { RDATA_WF_SHORT, RDATA_WF_ILNP64 }, { RDATA_ZF_SHORT, RDATA_ZF_ILNP64 } }, /* 107 */ { TYPE_LP, "LP", T_LP, 2, 2, { RDATA_WF_SHORT, RDATA_WF_UNCOMPRESSED_DNAME }, { RDATA_ZF_SHORT, RDATA_ZF_DNAME } }, /* 108 */ { TYPE_EUI48, "EUI48", T_EUI48, 1, 1, { RDATA_WF_EUI48 }, { RDATA_ZF_EUI48 } }, /* 109 */ { TYPE_EUI64, "EUI64", T_EUI64, 1, 1, { RDATA_WF_EUI64 }, { RDATA_ZF_EUI64 } }, /* 110 */ { 110, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 111 */ { 111, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 112 */ { 112, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 113 */ { 113, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 114 */ { 114, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 115 */ { 115, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 116 */ { 116, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 117 */ { 117, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 118 */ { 118, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 119 */ { 119, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 120 */ { 120, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 121 */ { 121, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 122 */ { 122, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 123 */ { 123, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 124 */ { 124, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 125 */ { 125, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 126 */ { 126, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 127 */ { 127, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 128 */ { 128, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 129 */ { 129, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 130 */ { 130, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 131 */ { 131, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 132 */ { 132, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 133 */ { 133, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 134 */ { 134, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 135 */ { 135, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 136 */ { 136, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 137 */ { 137, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 138 */ { 138, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 139 */ { 139, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 140 */ { 140, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 141 */ { 141, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 142 */ { 142, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 143 */ { 143, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 144 */ { 144, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 145 */ { 145, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 146 */ { 146, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 147 */ { 147, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 148 */ { 148, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 149 */ { 149, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 150 */ { 150, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 151 */ { 151, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 152 */ { 152, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 153 */ { 153, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 154 */ { 154, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 155 */ { 155, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 156 */ { 156, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 157 */ { 157, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 158 */ { 158, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 159 */ { 159, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 160 */ { 160, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 161 */ { 161, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 162 */ { 162, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 163 */ { 163, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 164 */ { 164, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 165 */ { 165, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 166 */ { 166, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 167 */ { 167, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 168 */ { 168, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 169 */ { 169, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 170 */ { 170, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 171 */ { 171, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 172 */ { 172, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 173 */ { 173, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 174 */ { 174, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 175 */ { 175, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 176 */ { 176, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 177 */ { 177, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 178 */ { 178, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 179 */ { 179, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 180 */ { 180, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 181 */ { 181, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 182 */ { 182, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 183 */ { 183, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 184 */ { 184, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 185 */ { 185, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 186 */ { 186, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 187 */ { 187, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 188 */ { 188, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 189 */ { 189, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 190 */ { 190, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 191 */ { 191, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 192 */ { 192, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 193 */ { 193, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 194 */ { 194, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 195 */ { 195, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 196 */ { 196, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 197 */ { 197, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 198 */ { 198, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 199 */ { 199, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 200 */ { 200, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 201 */ { 201, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 202 */ { 202, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 203 */ { 203, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 204 */ { 204, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 205 */ { 205, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 206 */ { 206, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 207 */ { 207, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 208 */ { 208, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 209 */ { 209, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 210 */ { 210, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 211 */ { 211, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 212 */ { 212, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 213 */ { 213, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 214 */ { 214, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 215 */ { 215, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 216 */ { 216, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 217 */ { 217, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 218 */ { 218, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 219 */ { 219, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 220 */ { 220, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 221 */ { 221, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 222 */ { 222, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 223 */ { 223, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 224 */ { 224, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 225 */ { 225, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 226 */ { 226, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 227 */ { 227, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 228 */ { 228, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 229 */ { 229, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 230 */ { 230, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 231 */ { 231, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 232 */ { 232, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 233 */ { 233, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 234 */ { 234, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 235 */ { 235, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 236 */ { 236, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 237 */ { 237, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 238 */ { 238, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 239 */ { 239, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 240 */ { 240, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 241 */ { 241, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 242 */ { 242, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 243 */ { 243, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 244 */ { 244, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 245 */ { 245, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 246 */ { 246, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 247 */ { 247, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 248 */ { 248, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 249 - TKEY [RFC 2930] */ { 249, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 250 - TSIG [RFC 2845] */ { 250, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 251 - IXFR [RFC 1995] */ { 251, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 252 - AXFR [RFC 1035, RFC 5936] */ { 252, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 253 - MAILB [RFC 1035] */ { 253, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 254 - MAILA [RFC 1035] */ { 254, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 255 - * [RFC 1035, RFC 6895] */ { 255, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 256 - URI */ { TYPE_URI, "URI", T_URI, 3, 3, { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_LONG_TEXT }, { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_LONG_TEXT } }, /* 257 - CAA [RFC 6844] */ { TYPE_CAA, "CAA", T_CAA, 3, 3, { RDATA_WF_BYTE, RDATA_WF_TEXT, RDATA_WF_LONG_TEXT }, { RDATA_ZF_BYTE, RDATA_ZF_TAG, RDATA_ZF_LONG_TEXT } }, /* 258 - AVC */ { TYPE_AVC, "AVC", T_AVC, 1, 1, { RDATA_WF_TEXTS }, { RDATA_ZF_TEXTS } }, /* 32768 - TA */ /* 32769 */ { TYPE_DLV, "DLV", T_DLV, 4, 4, { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY }, { RDATA_ZF_SHORT, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_HEX } }, }; rrtype_descriptor_type * rrtype_descriptor_by_type(uint16_t type) { if (type < RRTYPE_DESCRIPTORS_LENGTH) return &rrtype_descriptors[type]; else if (type == TYPE_DLV) return &rrtype_descriptors[PSEUDO_TYPE_DLV]; return &rrtype_descriptors[0]; } rrtype_descriptor_type * rrtype_descriptor_by_name(const char *name) { int i; for (i = 0; i < RRTYPE_DESCRIPTORS_LENGTH; ++i) { if (rrtype_descriptors[i].name && strcasecmp(rrtype_descriptors[i].name, name) == 0) { return &rrtype_descriptors[i]; } } if (rrtype_descriptors[PSEUDO_TYPE_DLV].name && strcasecmp(rrtype_descriptors[PSEUDO_TYPE_DLV].name, name) == 0) { return &rrtype_descriptors[PSEUDO_TYPE_DLV]; } return NULL; } const char * rrtype_to_string(uint16_t rrtype) { static char buf[20]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); if (descriptor->name) { return descriptor->name; } else { snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype); return buf; } } /* * Lookup the type in the ztypes lookup table. If not found, check if * the type uses the "TYPExxx" notation for unknown types. * * Return 0 if no type matches. */ uint16_t rrtype_from_string(const char *name) { char *end; long rrtype; rrtype_descriptor_type *entry; /* Because this routine is called during zone parse for every record, * we optimise for frequently occurring records. * Also, we optimise for 'IN' and numbers are not rr types, because * during parse this routine is called for every rr class and TTL * to determine that it is not an RR type */ switch(name[0]) { case 'r': case 'R': if(strcasecmp(name+1, "RSIG") == 0) return TYPE_RRSIG; break; case 'n': case 'N': switch(name[1]) { case 's': case 'S': switch(name[2]) { case 0: return TYPE_NS; case 'e': case 'E': if(strcasecmp(name+2, "EC") == 0) return TYPE_NSEC; if(strcasecmp(name+2, "EC3") == 0) return TYPE_NSEC3; if(strcasecmp(name+2, "EC3PARAM") == 0) return TYPE_NSEC3PARAM; break; } break; } break; case 'd': case 'D': switch(name[1]) { case 's': case 'S': if(name[2]==0) return TYPE_DS; break; case 'n': case 'N': if(strcasecmp(name+2, "SKEY") == 0) return TYPE_DNSKEY; break; } break; case 'a': case 'A': switch(name[1]) { case 0: return TYPE_A; case 'a': case 'A': if(strcasecmp(name+2, "AA") == 0) return TYPE_AAAA; break; } break; case 's': case 'S': if(strcasecmp(name+1, "OA") == 0) return TYPE_SOA; break; case 't': case 'T': if(strcasecmp(name+1, "XT") == 0) return TYPE_TXT; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return 0; /* no RR types start with 0-9 */ case 'i': case 'I': switch(name[1]) { case 'n': case 'N': return 0; /* 'IN' is a class not a type */ } break; } entry = rrtype_descriptor_by_name(name); if (entry) { return entry->type; } if (strlen(name) < 5) return 0; if (strncasecmp(name, "TYPE", 4) != 0) return 0; if (!isdigit((unsigned char)name[4])) return 0; /* The rest from the string must be a number. */ rrtype = strtol(name + 4, &end, 10); if (*end != '\0') return 0; if (rrtype < 0 || rrtype > 65535L) return 0; return (uint16_t) rrtype; } const char * rrclass_to_string(uint16_t rrclass) { static char buf[20]; lookup_table_type *entry = lookup_by_id(dns_rrclasses, rrclass); if (entry) { assert(strlen(entry->name) < sizeof(buf)); strlcpy(buf, entry->name, sizeof(buf)); } else { snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass); } return buf; } uint16_t rrclass_from_string(const char *name) { char *end; long rrclass; lookup_table_type *entry; entry = lookup_by_name(dns_rrclasses, name); if (entry) { return (uint16_t) entry->id; } if (strlen(name) < 6) return 0; if (strncasecmp(name, "CLASS", 5) != 0) return 0; if (!isdigit((unsigned char)name[5])) return 0; /* The rest from the string must be a number. */ rrclass = strtol(name + 5, &end, 10); if (*end != '\0') return 0; if (rrclass < 0 || rrclass > 65535L) return 0; return (uint16_t) rrclass; } nsd-4.1.26/zparser.c0000664000175000017500000041067013401455024013666 0ustar wouterwouter/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Copy the first part of user declarations. */ #line 1 "zparser.y" /* yacc.c:339 */ /* * zyparser.y -- yacc grammar for (DNS) zone files * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include "dname.h" #include "namedb.h" #include "zonec.h" /* these need to be global, otherwise they cannot be used inside yacc */ zparser_type *parser; #ifdef __cplusplus extern "C" #endif /* __cplusplus */ int yywrap(void); /* this hold the nxt bits */ static uint8_t nxtbits[16]; static int dlv_warn = 1; /* 256 windows of 256 bits (32 bytes) */ /* still need to reset the bastard somewhere */ static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]; /* hold the highest rcode seen in a NSEC rdata , BUG #106 */ uint16_t nsec_highest_rcode; void yyerror(const char *message); #ifdef NSEC3 /* parse nsec3 parameters and add the (first) rdata elements */ static void nsec3_add_params(const char* hash_algo_str, const char* flag_str, const char* iter_str, const char* salt_str, int salt_len); #endif /* NSEC3 */ #line 116 "zparser.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "zparser.h". */ #ifndef YY_YY_ZPARSER_H_INCLUDED # define YY_YY_ZPARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { T_A = 258, T_NS = 259, T_MX = 260, T_TXT = 261, T_CNAME = 262, T_AAAA = 263, T_PTR = 264, T_NXT = 265, T_KEY = 266, T_SOA = 267, T_SIG = 268, T_SRV = 269, T_CERT = 270, T_LOC = 271, T_MD = 272, T_MF = 273, T_MB = 274, T_MG = 275, T_MR = 276, T_NULL = 277, T_WKS = 278, T_HINFO = 279, T_MINFO = 280, T_RP = 281, T_AFSDB = 282, T_X25 = 283, T_ISDN = 284, T_RT = 285, T_NSAP = 286, T_NSAP_PTR = 287, T_PX = 288, T_GPOS = 289, T_EID = 290, T_NIMLOC = 291, T_ATMA = 292, T_NAPTR = 293, T_KX = 294, T_A6 = 295, T_DNAME = 296, T_SINK = 297, T_OPT = 298, T_APL = 299, T_UINFO = 300, T_UID = 301, T_GID = 302, T_UNSPEC = 303, T_TKEY = 304, T_TSIG = 305, T_IXFR = 306, T_AXFR = 307, T_MAILB = 308, T_MAILA = 309, T_DS = 310, T_DLV = 311, T_SSHFP = 312, T_RRSIG = 313, T_NSEC = 314, T_DNSKEY = 315, T_SPF = 316, T_NSEC3 = 317, T_IPSECKEY = 318, T_DHCID = 319, T_NSEC3PARAM = 320, T_TLSA = 321, T_URI = 322, T_NID = 323, T_L32 = 324, T_L64 = 325, T_LP = 326, T_EUI48 = 327, T_EUI64 = 328, T_CAA = 329, T_CDS = 330, T_CDNSKEY = 331, T_OPENPGPKEY = 332, T_CSYNC = 333, T_AVC = 334, T_SMIMEA = 335, DOLLAR_TTL = 336, DOLLAR_ORIGIN = 337, NL = 338, SP = 339, STR = 340, PREV = 341, BITLAB = 342, T_TTL = 343, T_RRCLASS = 344, URR = 345, T_UTYPE = 346 }; #endif /* Tokens. */ #define T_A 258 #define T_NS 259 #define T_MX 260 #define T_TXT 261 #define T_CNAME 262 #define T_AAAA 263 #define T_PTR 264 #define T_NXT 265 #define T_KEY 266 #define T_SOA 267 #define T_SIG 268 #define T_SRV 269 #define T_CERT 270 #define T_LOC 271 #define T_MD 272 #define T_MF 273 #define T_MB 274 #define T_MG 275 #define T_MR 276 #define T_NULL 277 #define T_WKS 278 #define T_HINFO 279 #define T_MINFO 280 #define T_RP 281 #define T_AFSDB 282 #define T_X25 283 #define T_ISDN 284 #define T_RT 285 #define T_NSAP 286 #define T_NSAP_PTR 287 #define T_PX 288 #define T_GPOS 289 #define T_EID 290 #define T_NIMLOC 291 #define T_ATMA 292 #define T_NAPTR 293 #define T_KX 294 #define T_A6 295 #define T_DNAME 296 #define T_SINK 297 #define T_OPT 298 #define T_APL 299 #define T_UINFO 300 #define T_UID 301 #define T_GID 302 #define T_UNSPEC 303 #define T_TKEY 304 #define T_TSIG 305 #define T_IXFR 306 #define T_AXFR 307 #define T_MAILB 308 #define T_MAILA 309 #define T_DS 310 #define T_DLV 311 #define T_SSHFP 312 #define T_RRSIG 313 #define T_NSEC 314 #define T_DNSKEY 315 #define T_SPF 316 #define T_NSEC3 317 #define T_IPSECKEY 318 #define T_DHCID 319 #define T_NSEC3PARAM 320 #define T_TLSA 321 #define T_URI 322 #define T_NID 323 #define T_L32 324 #define T_L64 325 #define T_LP 326 #define T_EUI48 327 #define T_EUI64 328 #define T_CAA 329 #define T_CDS 330 #define T_CDNSKEY 331 #define T_OPENPGPKEY 332 #define T_CSYNC 333 #define T_AVC 334 #define T_SMIMEA 335 #define DOLLAR_TTL 336 #define DOLLAR_ORIGIN 337 #define NL 338 #define SP 339 #define STR 340 #define PREV 341 #define BITLAB 342 #define T_TTL 343 #define T_RRCLASS 344 #define URR 345 #define T_UTYPE 346 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 50 "zparser.y" /* yacc.c:355 */ domain_type *domain; const dname_type *dname; struct lex_data data; uint32_t ttl; uint16_t klass; uint16_t type; uint16_t *unknown; #line 348 "zparser.c" /* yacc.c:355 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_ZPARSER_H_INCLUDED */ /* Copy the second part of user declarations. */ #line 365 "zparser.c" /* yacc.c:358 */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 961 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 94 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 75 /* YYNRULES -- Number of rules. */ #define YYNRULES 237 /* YYNSTATES -- Number of states. */ #define YYNSTATES 587 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 346 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 92, 92, 93, 96, 97, 98, 99, 107, 115, 135, 139, 140, 143, 144, 147, 157, 168, 174, 181, 186, 193, 197, 202, 207, 212, 219, 220, 241, 245, 249, 259, 273, 280, 281, 299, 300, 324, 331, 343, 355, 372, 373, 385, 389, 399, 400, 405, 414, 426, 435, 446, 449, 452, 466, 467, 474, 475, 491, 492, 507, 508, 513, 523, 541, 542, 543, 544, 545, 546, 551, 552, 558, 559, 560, 561, 562, 563, 569, 570, 571, 572, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 688, 694, 701, 714, 721, 728, 736, 743, 750, 758, 766, 773, 777, 785, 793, 805, 813, 819, 825, 833, 843, 855, 863, 873, 876, 880, 886, 895, 904, 912, 918, 933, 943, 958, 968, 977, 986, 995, 1036, 1040, 1044, 1051, 1058, 1065, 1072, 1078, 1085, 1094, 1103, 1110, 1120, 1126, 1130 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "T_A", "T_NS", "T_MX", "T_TXT", "T_CNAME", "T_AAAA", "T_PTR", "T_NXT", "T_KEY", "T_SOA", "T_SIG", "T_SRV", "T_CERT", "T_LOC", "T_MD", "T_MF", "T_MB", "T_MG", "T_MR", "T_NULL", "T_WKS", "T_HINFO", "T_MINFO", "T_RP", "T_AFSDB", "T_X25", "T_ISDN", "T_RT", "T_NSAP", "T_NSAP_PTR", "T_PX", "T_GPOS", "T_EID", "T_NIMLOC", "T_ATMA", "T_NAPTR", "T_KX", "T_A6", "T_DNAME", "T_SINK", "T_OPT", "T_APL", "T_UINFO", "T_UID", "T_GID", "T_UNSPEC", "T_TKEY", "T_TSIG", "T_IXFR", "T_AXFR", "T_MAILB", "T_MAILA", "T_DS", "T_DLV", "T_SSHFP", "T_RRSIG", "T_NSEC", "T_DNSKEY", "T_SPF", "T_NSEC3", "T_IPSECKEY", "T_DHCID", "T_NSEC3PARAM", "T_TLSA", "T_URI", "T_NID", "T_L32", "T_L64", "T_LP", "T_EUI48", "T_EUI64", "T_CAA", "T_CDS", "T_CDNSKEY", "T_OPENPGPKEY", "T_CSYNC", "T_AVC", "T_SMIMEA", "DOLLAR_TTL", "DOLLAR_ORIGIN", "NL", "SP", "STR", "PREV", "BITLAB", "T_TTL", "T_RRCLASS", "URR", "T_UTYPE", "'.'", "'@'", "$accept", "lines", "line", "sp", "trail", "ttl_directive", "origin_directive", "rr", "owner", "classttl", "dname", "abs_dname", "label", "rel_dname", "wire_dname", "wire_abs_dname", "wire_label", "wire_rel_dname", "str_seq", "concatenated_str_seq", "nxt_seq", "nsec_more", "nsec_seq", "str_sp_seq", "str_dot_seq", "dotted_str", "type_and_rdata", "rdata_a", "rdata_domain_name", "rdata_soa", "rdata_wks", "rdata_hinfo", "rdata_minfo", "rdata_mx", "rdata_txt", "rdata_rp", "rdata_afsdb", "rdata_x25", "rdata_isdn", "rdata_rt", "rdata_nsap", "rdata_px", "rdata_aaaa", "rdata_loc", "rdata_nxt", "rdata_srv", "rdata_naptr", "rdata_kx", "rdata_cert", "rdata_apl", "rdata_apl_seq", "rdata_ds", "rdata_dlv", "rdata_sshfp", "rdata_dhcid", "rdata_rrsig", "rdata_nsec", "rdata_nsec3", "rdata_nsec3_param", "rdata_tlsa", "rdata_smimea", "rdata_dnskey", "rdata_ipsec_base", "rdata_ipseckey", "rdata_nid", "rdata_l32", "rdata_l64", "rdata_lp", "rdata_eui48", "rdata_eui64", "rdata_uri", "rdata_caa", "rdata_openpgpkey", "rdata_csync", "rdata_unknown", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 46, 64 }; # endif #define YYPACT_NINF -445 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-445))) #define YYTABLE_NINF -1 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { -445, 138, -445, -78, -72, -72, -445, -445, -445, -56, -445, -445, -445, -445, 17, -445, -445, -445, 89, -72, -445, -445, -58, -445, 130, 28, -445, -445, -445, -72, -72, 809, 30, 32, 207, 207, 45, -54, 85, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, 207, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, 121, -72, -445, -445, -445, 267, -445, -445, -445, -72, -72, 75, 18, -53, 75, 18, 75, 18, 18, 96, 18, 103, 105, 107, 78, 18, 18, 18, 18, 18, 75, 116, 18, 18, 119, 128, 143, 152, 155, 159, 168, 181, 18, 42, -445, 183, 192, 195, 103, -77, 96, 75, 199, 202, 218, 221, 230, 233, 243, 245, 252, 255, 262, 269, 273, 183, 96, 218, 277, 75, 280, 50, 71, -445, 30, 30, -445, 13, -445, 62, -445, -445, 207, -445, -445, -72, -445, -445, 207, 43, -445, -445, -445, -445, 62, -445, -445, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -445, -445, 64, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -59, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, 207, -445, -445, 207, -445, -445, -72, -445, -445, -445, 74, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -445, -445, 43, -445, 207, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -445, -445, -445, -445, -445, 285, -445, -445, 58, -445, -445, -445, -445, -445, -445, -72, -445, -445, -72, 207, -445, -445, -445, 207, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, -72, -445, -445, 207, -445, -445, 207, -445, -445, -72, -445, -445, -445, -445, -445, -445, 207, -445, -445, -72, -445, -445, -445, -445, -72, -445, -445, -445, -445, 70, 309, 79, -445, -445, 28, 57, -445, -445, 311, 314, 28, 320, 325, 329, 99, 171, -445, 332, 342, 28, 28, 28, -445, 210, -445, 28, 109, -445, 28, 345, 28, 57, -445, 347, 349, 354, -445, 288, -445, 113, 360, 362, 295, -445, 304, -445, 373, 378, 382, 87, 87, 87, 28, -445, -445, 384, -445, 391, 393, -445, 207, -445, 207, 43, -445, 207, -72, -72, -72, -72, -72, -445, -445, -72, 207, 207, 207, 207, 207, 207, -445, -72, -72, 207, 43, -72, -72, -72, -445, 288, 285, -445, -445, -72, -72, 207, -445, -72, -72, -72, 62, 62, 62, 207, -72, 285, -72, 295, -445, -445, 307, -445, 398, 400, 402, 405, 407, 91, -445, -445, -445, -445, -445, -445, 28, 410, -445, 414, 436, 438, -445, -445, 448, 450, -445, 452, 464, 87, -445, -445, -445, -445, 87, -445, 468, 207, -445, -72, -72, -72, -72, -72, 64, 207, -72, -72, -72, 207, -72, -72, -72, -72, 62, 62, -72, -445, 438, 472, 475, 28, 438, -445, -445, 477, 438, 438, -445, 485, 87, 490, 438, -445, -445, 438, 207, -72, -72, 207, 207, -72, 207, 207, -72, 43, 207, 207, 207, -445, 492, 496, -445, -445, 501, -445, -445, 503, -445, -445, -445, -72, -72, -72, 285, 505, 507, 28, -445, -72, -72, 207, 509, 511, -445, 207, -72, -445, 59, -72, 438, 207, -445 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 1, 0, 0, 0, 4, 11, 31, 20, 32, 28, 29, 3, 0, 7, 8, 9, 21, 0, 26, 33, 27, 10, 0, 0, 6, 5, 12, 0, 0, 0, 19, 30, 0, 0, 0, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 34, 13, 0, 15, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 24, 25, 60, 0, 61, 0, 64, 65, 0, 66, 67, 0, 90, 91, 0, 43, 92, 93, 72, 73, 0, 120, 121, 84, 85, 0, 124, 125, 0, 116, 117, 0, 74, 75, 0, 114, 115, 0, 126, 127, 0, 132, 133, 45, 46, 0, 122, 123, 68, 69, 70, 71, 76, 77, 78, 79, 80, 81, 0, 82, 83, 0, 86, 87, 0, 88, 89, 0, 98, 99, 0, 100, 101, 0, 102, 103, 0, 104, 105, 0, 110, 111, 58, 0, 112, 113, 0, 118, 119, 0, 128, 129, 0, 130, 131, 134, 135, 209, 137, 0, 138, 0, 139, 140, 0, 141, 142, 0, 143, 144, 145, 146, 40, 37, 38, 0, 35, 41, 36, 147, 148, 153, 154, 94, 95, 0, 149, 150, 0, 0, 106, 107, 56, 0, 108, 109, 0, 151, 152, 0, 155, 156, 0, 181, 182, 0, 159, 160, 0, 161, 162, 0, 163, 164, 0, 165, 166, 0, 167, 168, 0, 169, 170, 0, 171, 172, 173, 174, 175, 176, 0, 177, 178, 0, 179, 180, 96, 97, 0, 157, 158, 184, 183, 0, 0, 62, 185, 186, 0, 0, 192, 201, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 195, 0, 196, 0, 0, 199, 0, 0, 0, 0, 208, 0, 0, 0, 54, 0, 216, 39, 0, 0, 0, 224, 0, 214, 0, 0, 0, 0, 0, 0, 0, 229, 230, 0, 233, 0, 0, 237, 0, 63, 0, 44, 49, 0, 0, 0, 0, 0, 0, 48, 47, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 210, 0, 0, 0, 52, 0, 0, 55, 42, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 191, 0, 203, 0, 0, 0, 0, 0, 0, 189, 190, 193, 194, 197, 198, 0, 0, 206, 0, 0, 0, 51, 53, 0, 0, 223, 0, 0, 0, 225, 226, 227, 228, 0, 234, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 188, 200, 0, 0, 0, 213, 0, 0, 0, 0, 231, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, 221, 0, 0, 204, 207, 0, 211, 212, 0, 218, 219, 220, 0, 0, 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 205, 0, 0, 187, 0, 0, 0, 0, 215 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -445, -445, -445, -1, 226, -445, -445, -445, -445, -445, 0, 182, 177, 201, -365, -445, -161, -445, -445, -227, -445, -197, -444, -66, -445, -5, -445, -445, -104, -445, -445, -445, -445, -445, -143, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, 88, -445, -445, -445, 118, -445, -445, -445, -445, -445, -138, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, -445, 791 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 1, 13, 103, 104, 15, 16, 17, 18, 31, 180, 20, 21, 22, 287, 288, 289, 290, 186, 217, 421, 447, 394, 305, 255, 187, 100, 178, 181, 204, 231, 234, 237, 184, 188, 240, 243, 246, 249, 252, 256, 259, 193, 218, 198, 210, 262, 265, 213, 270, 271, 274, 277, 280, 306, 207, 291, 298, 309, 312, 351, 201, 301, 302, 318, 321, 324, 327, 330, 333, 315, 336, 343, 346, 179 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint16 yytable[] = { 14, 19, 487, 24, 25, 23, 295, 28, 284, 190, 293, 195, 7, 175, 355, 285, 286, 499, 32, 220, 222, 224, 226, 228, 348, 7, 340, 26, 37, 38, 28, 28, 183, 357, 33, 107, 267, 175, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 7, 170, 342, 27, 28, 28, 8, 177, 10, 172, 173, 175, 192, 11, 12, 28, 8, 28, 10, 197, 8, 203, 10, 11, 12, 169, 230, 572, 171, 28, 174, 102, 7, 236, 239, 175, 353, 176, 357, 269, 33, 2, 3, 171, 28, 174, 28, 284, 102, 7, 102, 7, 176, 395, 285, 286, 415, 357, 28, 370, 102, 7, 28, 174, 175, 28, 215, 417, 175, 382, 176, 175, 28, 216, 28, 174, 108, 356, 28, 215, 29, 30, 176, 28, 200, 360, 216, 427, 361, 175, 28, 206, 28, 209, 28, 212, 175, 436, 175, 364, 175, 284, 365, 28, 233, 366, 28, 242, 367, 175, 35, 368, 175, 101, 369, 28, 245, 28, 34, 371, 583, 175, 4, 5, 6, 7, 8, 9, 10, 36, 28, 248, 373, 11, 12, 374, 175, 448, 375, 28, 251, 376, 28, 254, 377, 175, 28, 258, 175, 508, 379, 486, 175, 381, 338, 28, 261, 171, 28, 428, 384, 175, 0, 385, 105, 106, 386, 282, 28, 264, 28, 273, 0, 387, 175, 389, 175, 0, 390, 28, 276, 391, 28, 279, 0, 175, 28, 297, 175, 28, 300, 0, 175, 102, 7, 175, 171, 28, 434, 396, 142, 0, 397, 398, 0, 28, 304, 400, 28, 308, 402, 175, 0, 403, 175, 0, 404, 28, 311, 405, 28, 314, 406, 175, 0, 407, 175, 0, 408, 0, 28, 317, 28, 320, 0, 451, 175, 411, 175, 28, 323, 0, 28, 326, 400, 175, 0, 413, 175, 28, 329, 0, 414, 171, 28, 175, 28, 332, 0, 419, 28, 335, 175, 418, 28, 345, 175, 28, 350, 423, 175, 392, 393, 175, 444, 445, 446, 0, 431, 432, 433, 171, 28, 304, 435, 440, 0, 437, 0, 439, 171, 28, 452, 171, 28, 502, 28, 416, 28, 420, 501, 28, 422, 456, 457, 458, 358, 28, 424, 359, 0, 459, 28, 425, 0, 362, 28, 426, 463, 28, 429, 363, 513, 466, 468, 469, 470, 471, 472, 28, 430, 473, 28, 438, 28, 441, 28, 442, 0, 480, 481, 28, 443, 483, 484, 485, 372, 28, 449, 28, 450, 488, 489, 400, 0, 491, 492, 493, 0, 540, 28, 453, 498, 544, 500, 28, 454, 546, 547, 28, 455, 28, 460, 551, 378, 0, 552, 380, 28, 461, 28, 462, 0, 509, 383, 28, 503, 28, 504, 28, 505, 518, 28, 506, 28, 507, 519, 28, 510, 0, 388, 28, 511, 400, 0, 522, 523, 524, 525, 526, 371, 0, 529, 530, 531, 400, 533, 534, 535, 536, 0, 585, 539, 28, 512, 28, 304, 0, 543, 0, 399, 0, 549, 0, 401, 28, 514, 28, 515, 28, 516, 0, 400, 554, 555, 0, 400, 558, 400, 400, 561, 28, 517, 400, 400, 28, 520, 0, 409, 28, 541, 410, 28, 542, 28, 545, 0, 569, 570, 571, 0, 412, 28, 548, 575, 576, 577, 28, 550, 28, 565, 0, 582, 28, 566, 584, 0, 400, 28, 567, 28, 568, 28, 573, 28, 574, 28, 579, 28, 580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 464, 0, 465, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 0, 474, 475, 476, 477, 478, 479, 0, 0, 0, 482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 494, 495, 496, 497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 527, 528, 0, 0, 0, 532, 0, 0, 0, 0, 537, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, 556, 557, 0, 559, 560, 0, 0, 562, 563, 564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 578, 0, 0, 0, 581, 0, 0, 0, 0, 0, 586, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 58, 59, 60, 61, 62, 63, 64, 65, 66, 0, 67, 0, 0, 0, 0, 68, 69, 0, 70, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 99, 182, 185, 189, 191, 194, 196, 199, 202, 205, 208, 211, 214, 219, 221, 223, 225, 227, 229, 232, 235, 238, 241, 244, 247, 250, 253, 257, 260, 263, 266, 268, 272, 0, 275, 278, 281, 283, 292, 294, 296, 299, 303, 307, 310, 313, 316, 319, 322, 325, 328, 331, 334, 337, 339, 341, 344, 347, 349, 352, 0, 354 }; static const yytype_int16 yycheck[] = { 1, 1, 446, 4, 5, 83, 149, 84, 85, 113, 148, 115, 84, 90, 1, 92, 93, 461, 19, 123, 124, 125, 126, 127, 167, 84, 164, 83, 29, 30, 84, 84, 85, 92, 92, 89, 140, 90, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 84, 99, 165, 83, 84, 84, 85, 109, 87, 107, 108, 90, 114, 92, 93, 84, 85, 84, 87, 116, 85, 118, 87, 92, 93, 1, 128, 568, 83, 84, 85, 83, 84, 130, 131, 90, 83, 92, 92, 141, 92, 0, 1, 83, 84, 85, 84, 85, 83, 84, 83, 84, 92, 92, 92, 93, 83, 92, 84, 92, 83, 84, 84, 85, 90, 84, 85, 85, 90, 92, 92, 90, 84, 92, 84, 85, 88, 175, 84, 85, 88, 89, 92, 84, 85, 183, 92, 85, 186, 90, 84, 85, 84, 85, 84, 85, 90, 85, 90, 197, 90, 85, 200, 84, 85, 203, 84, 85, 206, 90, 25, 209, 90, 33, 212, 84, 85, 84, 85, 217, 582, 90, 81, 82, 83, 84, 85, 86, 87, 25, 84, 85, 230, 92, 93, 233, 90, 395, 236, 84, 85, 239, 84, 85, 242, 90, 84, 85, 90, 473, 248, 445, 90, 251, 163, 84, 85, 83, 84, 85, 258, 90, -1, 261, 35, 36, 264, 146, 84, 85, 84, 85, -1, 271, 90, 273, 90, -1, 276, 84, 85, 279, 84, 85, -1, 90, 84, 85, 90, 84, 85, -1, 90, 83, 84, 90, 83, 84, 85, 297, 71, -1, 300, 301, -1, 84, 85, 305, 84, 85, 308, 90, -1, 311, 90, -1, 314, 84, 85, 317, 84, 85, 320, 90, -1, 323, 90, -1, 326, -1, 84, 85, 84, 85, -1, 398, 90, 335, 90, 84, 85, -1, 84, 85, 342, 90, -1, 345, 90, 84, 85, -1, 350, 83, 84, 90, 84, 85, -1, 361, 84, 85, 90, 360, 84, 85, 90, 84, 85, 366, 90, 83, 84, 90, 83, 84, 85, -1, 375, 376, 377, 83, 84, 85, 381, 387, -1, 384, -1, 386, 83, 84, 85, 83, 84, 85, 84, 85, 84, 85, 463, 84, 85, 405, 406, 407, 177, 84, 85, 180, -1, 408, 84, 85, -1, 186, 84, 85, 416, 84, 85, 192, 485, 421, 422, 423, 424, 425, 426, 84, 85, 429, 84, 85, 84, 85, 84, 85, -1, 437, 438, 84, 85, 441, 442, 443, 217, 84, 85, 84, 85, 449, 450, 451, -1, 453, 454, 455, -1, 522, 84, 85, 460, 526, 462, 84, 85, 530, 531, 84, 85, 84, 85, 536, 245, -1, 539, 248, 84, 85, 84, 85, -1, 480, 255, 84, 85, 84, 85, 84, 85, 493, 84, 85, 84, 85, 498, 84, 85, -1, 271, 84, 85, 501, -1, 503, 504, 505, 506, 507, 508, -1, 510, 511, 512, 513, 514, 515, 516, 517, -1, 584, 520, 84, 85, 84, 85, -1, 525, -1, 301, -1, 534, -1, 305, 84, 85, 84, 85, 84, 85, -1, 540, 541, 542, -1, 544, 545, 546, 547, 548, 84, 85, 551, 552, 84, 85, -1, 329, 84, 85, 332, 84, 85, 84, 85, -1, 565, 566, 567, -1, 342, 84, 85, 571, 573, 574, 84, 85, 84, 85, -1, 580, 84, 85, 583, -1, 585, 84, 85, 84, 85, 84, 85, 84, 85, 84, 85, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 416, -1, 418, -1, -1, 421, -1, -1, -1, -1, -1, -1, -1, -1, 430, 431, 432, 433, 434, 435, -1, -1, -1, 439, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 451, -1, -1, -1, -1, 456, 457, 458, 459, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 501, -1, -1, -1, -1, -1, -1, 508, 509, -1, -1, -1, 513, -1, -1, -1, -1, 518, 519, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 540, -1, -1, 543, 544, -1, 546, 547, -1, -1, 550, 551, 552, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 575, -1, -1, -1, 579, -1, -1, -1, -1, -1, 585, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, -1, 33, -1, -1, -1, -1, 38, 39, -1, 41, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, -1, -1, -1, -1, 85, -1, -1, -1, -1, -1, 91, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, -1, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, -1, 170 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 95, 0, 1, 81, 82, 83, 84, 85, 86, 87, 92, 93, 96, 97, 99, 100, 101, 102, 104, 105, 106, 107, 83, 97, 97, 83, 83, 84, 88, 89, 103, 97, 92, 85, 105, 107, 97, 97, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 38, 39, 41, 44, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 85, 91, 120, 106, 83, 97, 98, 98, 98, 89, 88, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 1, 97, 83, 97, 97, 85, 90, 92, 119, 121, 168, 104, 122, 168, 85, 127, 168, 112, 119, 128, 168, 122, 168, 119, 136, 168, 122, 168, 104, 138, 168, 85, 155, 168, 104, 123, 168, 85, 149, 168, 85, 139, 168, 85, 142, 168, 85, 92, 113, 137, 168, 122, 168, 122, 168, 122, 168, 122, 168, 122, 168, 119, 124, 168, 85, 125, 168, 104, 126, 168, 104, 129, 168, 85, 130, 168, 85, 131, 168, 85, 132, 168, 85, 133, 168, 85, 118, 134, 168, 85, 135, 168, 85, 140, 168, 85, 141, 168, 122, 168, 119, 143, 144, 168, 85, 145, 168, 85, 146, 168, 85, 147, 168, 149, 168, 85, 92, 93, 108, 109, 110, 111, 150, 168, 155, 168, 128, 168, 85, 151, 168, 85, 156, 157, 168, 85, 117, 148, 168, 85, 152, 168, 85, 153, 168, 85, 164, 168, 85, 158, 168, 85, 159, 168, 85, 160, 168, 85, 161, 168, 85, 162, 168, 85, 163, 168, 85, 165, 168, 145, 168, 155, 168, 117, 166, 168, 85, 167, 168, 128, 168, 85, 154, 168, 83, 168, 1, 97, 92, 98, 98, 97, 97, 98, 98, 97, 97, 97, 97, 97, 97, 92, 97, 98, 97, 97, 97, 97, 97, 98, 97, 98, 97, 92, 98, 97, 97, 97, 97, 98, 97, 97, 97, 83, 84, 116, 92, 97, 97, 97, 98, 97, 98, 97, 97, 97, 97, 97, 97, 97, 98, 98, 97, 98, 97, 97, 83, 85, 85, 104, 119, 85, 114, 85, 104, 85, 85, 85, 85, 85, 85, 85, 104, 104, 104, 85, 104, 85, 104, 85, 104, 119, 85, 85, 85, 83, 84, 85, 115, 110, 85, 85, 117, 85, 85, 85, 85, 119, 119, 119, 104, 85, 85, 85, 97, 98, 98, 97, 98, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 97, 97, 98, 97, 97, 97, 115, 116, 97, 97, 98, 97, 97, 97, 98, 98, 98, 98, 97, 116, 97, 117, 85, 85, 85, 85, 85, 85, 113, 104, 85, 85, 85, 117, 85, 85, 85, 85, 119, 119, 85, 98, 97, 97, 97, 97, 97, 98, 98, 97, 97, 97, 98, 97, 97, 97, 97, 98, 98, 97, 117, 85, 85, 104, 117, 85, 117, 117, 85, 119, 85, 117, 117, 98, 97, 97, 98, 98, 97, 98, 98, 97, 98, 98, 98, 85, 85, 85, 85, 97, 97, 97, 116, 85, 85, 104, 97, 97, 98, 85, 85, 98, 97, 108, 97, 117, 98 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 94, 95, 95, 96, 96, 96, 96, 96, 96, 96, 97, 97, 98, 98, 99, 100, 100, 101, 102, 102, 103, 103, 103, 103, 103, 104, 104, 105, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 109, 110, 111, 111, 112, 112, 113, 113, 113, 113, 114, 114, 115, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 4, 4, 4, 3, 2, 1, 0, 2, 2, 4, 4, 1, 1, 1, 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 3, 1, 3, 1, 1, 3, 3, 1, 3, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 14, 6, 4, 4, 4, 2, 4, 4, 2, 2, 4, 4, 2, 6, 2, 2, 4, 8, 12, 4, 8, 2, 1, 3, 8, 8, 6, 2, 18, 2, 10, 8, 8, 8, 8, 7, 4, 2, 4, 4, 4, 4, 2, 2, 6, 6, 2, 4, 6, 4, 3 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) { unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 6: #line 98 "zparser.y" /* yacc.c:1646 */ {} #line 1925 "zparser.c" /* yacc.c:1646 */ break; case 7: #line 100 "zparser.y" /* yacc.c:1646 */ { region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } #line 1937 "zparser.c" /* yacc.c:1646 */ break; case 8: #line 108 "zparser.y" /* yacc.c:1646 */ { region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } #line 1949 "zparser.c" /* yacc.c:1646 */ break; case 9: #line 116 "zparser.y" /* yacc.c:1646 */ { /* rr should be fully parsed */ if (!parser->error_occurred) { parser->current_rr.rdatas =(rdata_atom_type *)region_alloc_array_init( parser->region, parser->current_rr.rdatas, parser->current_rr.rdata_count, sizeof(rdata_atom_type)); process_rr(); } region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } #line 1973 "zparser.c" /* yacc.c:1646 */ break; case 15: #line 148 "zparser.y" /* yacc.c:1646 */ { parser->default_ttl = zparser_ttl2int((yyvsp[-1].data).str, &(parser->error_occurred)); if (parser->error_occurred == 1) { parser->default_ttl = DEFAULT_TTL; parser->error_occurred = 0; } } #line 1985 "zparser.c" /* yacc.c:1646 */ break; case 16: #line 158 "zparser.y" /* yacc.c:1646 */ { /* if previous origin is unused, remove it, do not leak it */ if(parser->origin != error_domain && parser->origin != (yyvsp[-1].domain)) { /* protect $3 from deletion, because deldomain walks up */ (yyvsp[-1].domain)->usage ++; domain_table_deldomain(parser->db, parser->origin); (yyvsp[-1].domain)->usage --; } parser->origin = (yyvsp[-1].domain); } #line 2000 "zparser.c" /* yacc.c:1646 */ break; case 17: #line 169 "zparser.y" /* yacc.c:1646 */ { zc_error_prev_line("$ORIGIN directive requires absolute domain name"); } #line 2008 "zparser.c" /* yacc.c:1646 */ break; case 18: #line 175 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.owner = (yyvsp[-2].domain); parser->current_rr.type = (yyvsp[0].type); } #line 2017 "zparser.c" /* yacc.c:1646 */ break; case 19: #line 182 "zparser.y" /* yacc.c:1646 */ { parser->prev_dname = (yyvsp[-1].domain); (yyval.domain) = (yyvsp[-1].domain); } #line 2026 "zparser.c" /* yacc.c:1646 */ break; case 20: #line 187 "zparser.y" /* yacc.c:1646 */ { (yyval.domain) = parser->prev_dname; } #line 2034 "zparser.c" /* yacc.c:1646 */ break; case 21: #line 193 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.ttl = parser->default_ttl; parser->current_rr.klass = parser->default_class; } #line 2043 "zparser.c" /* yacc.c:1646 */ break; case 22: #line 198 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.ttl = parser->default_ttl; parser->current_rr.klass = (yyvsp[-1].klass); } #line 2052 "zparser.c" /* yacc.c:1646 */ break; case 23: #line 203 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.ttl = (yyvsp[-1].ttl); parser->current_rr.klass = parser->default_class; } #line 2061 "zparser.c" /* yacc.c:1646 */ break; case 24: #line 208 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.ttl = (yyvsp[-3].ttl); parser->current_rr.klass = (yyvsp[-1].klass); } #line 2070 "zparser.c" /* yacc.c:1646 */ break; case 25: #line 213 "zparser.y" /* yacc.c:1646 */ { parser->current_rr.ttl = (yyvsp[-1].ttl); parser->current_rr.klass = (yyvsp[-3].klass); } #line 2079 "zparser.c" /* yacc.c:1646 */ break; case 27: #line 221 "zparser.y" /* yacc.c:1646 */ { if ((yyvsp[0].dname) == error_dname) { (yyval.domain) = error_domain; } else if(parser->origin == error_domain) { zc_error("cannot concatenate origin to domain name, because origin failed to parse"); (yyval.domain) = error_domain; } else if ((yyvsp[0].dname)->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) { zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.domain) = error_domain; } else { (yyval.domain) = domain_table_insert( parser->db->domains, dname_concatenate( parser->rr_region, (yyvsp[0].dname), domain_dname(parser->origin))); } } #line 2102 "zparser.c" /* yacc.c:1646 */ break; case 28: #line 242 "zparser.y" /* yacc.c:1646 */ { (yyval.domain) = parser->db->domains->root; } #line 2110 "zparser.c" /* yacc.c:1646 */ break; case 29: #line 246 "zparser.y" /* yacc.c:1646 */ { (yyval.domain) = parser->origin; } #line 2118 "zparser.c" /* yacc.c:1646 */ break; case 30: #line 250 "zparser.y" /* yacc.c:1646 */ { if ((yyvsp[-1].dname) != error_dname) { (yyval.domain) = domain_table_insert(parser->db->domains, (yyvsp[-1].dname)); } else { (yyval.domain) = error_domain; } } #line 2130 "zparser.c" /* yacc.c:1646 */ break; case 31: #line 260 "zparser.y" /* yacc.c:1646 */ { if ((yyvsp[0].data).len > MAXLABELLEN) { zc_error("label exceeds %d character limit", MAXLABELLEN); (yyval.dname) = error_dname; } else if ((yyvsp[0].data).len <= 0) { zc_error("zero label length"); (yyval.dname) = error_dname; } else { (yyval.dname) = dname_make_from_label(parser->rr_region, (uint8_t *) (yyvsp[0].data).str, (yyvsp[0].data).len); } } #line 2148 "zparser.c" /* yacc.c:1646 */ break; case 32: #line 274 "zparser.y" /* yacc.c:1646 */ { zc_error("bitlabels are now deprecated. RFC2673 is obsoleted."); (yyval.dname) = error_dname; } #line 2157 "zparser.c" /* yacc.c:1646 */ break; case 34: #line 282 "zparser.y" /* yacc.c:1646 */ { if ((yyvsp[-2].dname) == error_dname || (yyvsp[0].dname) == error_dname) { (yyval.dname) = error_dname; } else if ((yyvsp[-2].dname)->name_size + (yyvsp[0].dname)->name_size - 1 > MAXDOMAINLEN) { zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.dname) = error_dname; } else { (yyval.dname) = dname_concatenate(parser->rr_region, (yyvsp[-2].dname), (yyvsp[0].dname)); } } #line 2173 "zparser.c" /* yacc.c:1646 */ break; case 36: #line 301 "zparser.y" /* yacc.c:1646 */ { /* terminate in root label and copy the origin in there */ if(parser->origin && domain_dname(parser->origin)) { (yyval.data).len = (yyvsp[0].data).len + domain_dname(parser->origin)->name_size; if ((yyval.data).len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); memmove((yyval.data).str, (yyvsp[0].data).str, (yyvsp[0].data).len); memmove((yyval.data).str + (yyvsp[0].data).len, dname_name(domain_dname(parser->origin)), domain_dname(parser->origin)->name_size); } else { (yyval.data).len = (yyvsp[0].data).len + 1; if ((yyval.data).len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); memmove((yyval.data).str, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str[ (yyvsp[0].data).len ] = 0; } } #line 2199 "zparser.c" /* yacc.c:1646 */ break; case 37: #line 325 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, 1); result[0] = 0; (yyval.data).str = result; (yyval.data).len = 1; } #line 2210 "zparser.c" /* yacc.c:1646 */ break; case 38: #line 332 "zparser.y" /* yacc.c:1646 */ { if(parser->origin && domain_dname(parser->origin)) { (yyval.data).len = domain_dname(parser->origin)->name_size; (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); memmove((yyval.data).str, dname_name(domain_dname(parser->origin)), (yyval.data).len); } else { (yyval.data).len = 1; (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); (yyval.data).str[0] = 0; } } #line 2226 "zparser.c" /* yacc.c:1646 */ break; case 39: #line 344 "zparser.y" /* yacc.c:1646 */ { (yyval.data).len = (yyvsp[-1].data).len + 1; if ((yyval.data).len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); memcpy((yyval.data).str, (yyvsp[-1].data).str, (yyvsp[-1].data).len); (yyval.data).str[(yyvsp[-1].data).len] = 0; } #line 2240 "zparser.c" /* yacc.c:1646 */ break; case 40: #line 356 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, (yyvsp[0].data).len + 1); if ((yyvsp[0].data).len > MAXLABELLEN) zc_error("label exceeds %d character limit", MAXLABELLEN); /* make label anyway */ result[0] = (yyvsp[0].data).len; memmove(result+1, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str = result; (yyval.data).len = (yyvsp[0].data).len + 1; } #line 2259 "zparser.c" /* yacc.c:1646 */ break; case 42: #line 374 "zparser.y" /* yacc.c:1646 */ { (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len; if ((yyval.data).len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len); memmove((yyval.data).str, (yyvsp[-2].data).str, (yyvsp[-2].data).len); memmove((yyval.data).str + (yyvsp[-2].data).len, (yyvsp[0].data).str, (yyvsp[0].data).len); } #line 2273 "zparser.c" /* yacc.c:1646 */ break; case 43: #line 386 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, (yyvsp[0].data).str, (yyvsp[0].data).len), 1); } #line 2281 "zparser.c" /* yacc.c:1646 */ break; case 44: #line 390 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, (yyvsp[0].data).str, (yyvsp[0].data).len), 0); } #line 2289 "zparser.c" /* yacc.c:1646 */ break; case 46: #line 401 "zparser.y" /* yacc.c:1646 */ { (yyval.data).len = 1; (yyval.data).str = region_strdup(parser->rr_region, "."); } #line 2298 "zparser.c" /* yacc.c:1646 */ break; case 47: #line 406 "zparser.y" /* yacc.c:1646 */ { (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len + 1; (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len + 1); memcpy((yyval.data).str, (yyvsp[-2].data).str, (yyvsp[-2].data).len); memcpy((yyval.data).str + (yyvsp[-2].data).len, " ", 1); memcpy((yyval.data).str + (yyvsp[-2].data).len + 1, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str[(yyval.data).len] = '\0'; } #line 2311 "zparser.c" /* yacc.c:1646 */ break; case 48: #line 415 "zparser.y" /* yacc.c:1646 */ { (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len + 1; (yyval.data).str = (char *) region_alloc(parser->rr_region, (yyval.data).len + 1); memcpy((yyval.data).str, (yyvsp[-2].data).str, (yyvsp[-2].data).len); memcpy((yyval.data).str + (yyvsp[-2].data).len, ".", 1); memcpy((yyval.data).str + (yyvsp[-2].data).len + 1, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str[(yyval.data).len] = '\0'; } #line 2324 "zparser.c" /* yacc.c:1646 */ break; case 49: #line 427 "zparser.y" /* yacc.c:1646 */ { uint16_t type = rrtype_from_string((yyvsp[0].data).str); if (type != 0 && type < 128) { set_bit(nxtbits, type); } else { zc_error("bad type %d in NXT record", (int) type); } } #line 2337 "zparser.c" /* yacc.c:1646 */ break; case 50: #line 436 "zparser.y" /* yacc.c:1646 */ { uint16_t type = rrtype_from_string((yyvsp[0].data).str); if (type != 0 && type < 128) { set_bit(nxtbits, type); } else { zc_error("bad type %d in NXT record", (int) type); } } #line 2350 "zparser.c" /* yacc.c:1646 */ break; case 51: #line 447 "zparser.y" /* yacc.c:1646 */ { } #line 2357 "zparser.c" /* yacc.c:1646 */ break; case 52: #line 450 "zparser.y" /* yacc.c:1646 */ { } #line 2364 "zparser.c" /* yacc.c:1646 */ break; case 53: #line 453 "zparser.y" /* yacc.c:1646 */ { uint16_t type = rrtype_from_string((yyvsp[-1].data).str); if (type != 0) { if (type > nsec_highest_rcode) { nsec_highest_rcode = type; } set_bitnsec(nsecbits, type); } else { zc_error("bad type %d in NSEC record", (int) type); } } #line 2380 "zparser.c" /* yacc.c:1646 */ break; case 57: #line 476 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, (yyvsp[-2].data).len + (yyvsp[0].data).len + 1); memcpy(result, (yyvsp[-2].data).str, (yyvsp[-2].data).len); memcpy(result + (yyvsp[-2].data).len, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str = result; (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len; (yyval.data).str[(yyval.data).len] = '\0'; } #line 2394 "zparser.c" /* yacc.c:1646 */ break; case 59: #line 493 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, (yyvsp[-2].data).len + (yyvsp[0].data).len + 1); memcpy(result, (yyvsp[-2].data).str, (yyvsp[-2].data).len); memcpy(result + (yyvsp[-2].data).len, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str = result; (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len; (yyval.data).str[(yyval.data).len] = '\0'; } #line 2408 "zparser.c" /* yacc.c:1646 */ break; case 61: #line 509 "zparser.y" /* yacc.c:1646 */ { (yyval.data).str = "."; (yyval.data).len = 1; } #line 2417 "zparser.c" /* yacc.c:1646 */ break; case 62: #line 514 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, (yyvsp[-1].data).len + 2); memcpy(result, (yyvsp[-1].data).str, (yyvsp[-1].data).len); result[(yyvsp[-1].data).len] = '.'; (yyval.data).str = result; (yyval.data).len = (yyvsp[-1].data).len + 1; (yyval.data).str[(yyval.data).len] = '\0'; } #line 2431 "zparser.c" /* yacc.c:1646 */ break; case 63: #line 524 "zparser.y" /* yacc.c:1646 */ { char *result = (char *) region_alloc(parser->rr_region, (yyvsp[-2].data).len + (yyvsp[0].data).len + 2); memcpy(result, (yyvsp[-2].data).str, (yyvsp[-2].data).len); result[(yyvsp[-2].data).len] = '.'; memcpy(result + (yyvsp[-2].data).len + 1, (yyvsp[0].data).str, (yyvsp[0].data).len); (yyval.data).str = result; (yyval.data).len = (yyvsp[-2].data).len + (yyvsp[0].data).len + 1; (yyval.data).str[(yyval.data).len] = '\0'; } #line 2446 "zparser.c" /* yacc.c:1646 */ break; case 65: #line 542 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2452 "zparser.c" /* yacc.c:1646 */ break; case 67: #line 544 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2458 "zparser.c" /* yacc.c:1646 */ break; case 68: #line 545 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MD is obsolete"); } #line 2464 "zparser.c" /* yacc.c:1646 */ break; case 69: #line 547 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MD is obsolete"); (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2473 "zparser.c" /* yacc.c:1646 */ break; case 70: #line 551 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MF is obsolete"); } #line 2479 "zparser.c" /* yacc.c:1646 */ break; case 71: #line 553 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MF is obsolete"); (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2489 "zparser.c" /* yacc.c:1646 */ break; case 73: #line 559 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2495 "zparser.c" /* yacc.c:1646 */ break; case 75: #line 561 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2501 "zparser.c" /* yacc.c:1646 */ break; case 76: #line 562 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MB is obsolete"); } #line 2507 "zparser.c" /* yacc.c:1646 */ break; case 77: #line 564 "zparser.y" /* yacc.c:1646 */ { zc_warning_prev_line("MB is obsolete"); (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2517 "zparser.c" /* yacc.c:1646 */ break; case 79: #line 570 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2523 "zparser.c" /* yacc.c:1646 */ break; case 81: #line 572 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2529 "zparser.c" /* yacc.c:1646 */ break; case 83: #line 575 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2535 "zparser.c" /* yacc.c:1646 */ break; case 85: #line 577 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2541 "zparser.c" /* yacc.c:1646 */ break; case 87: #line 579 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2547 "zparser.c" /* yacc.c:1646 */ break; case 89: #line 581 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2553 "zparser.c" /* yacc.c:1646 */ break; case 91: #line 583 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2559 "zparser.c" /* yacc.c:1646 */ break; case 93: #line 585 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2565 "zparser.c" /* yacc.c:1646 */ break; case 95: #line 587 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2571 "zparser.c" /* yacc.c:1646 */ break; case 97: #line 589 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2577 "zparser.c" /* yacc.c:1646 */ break; case 99: #line 591 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2583 "zparser.c" /* yacc.c:1646 */ break; case 101: #line 593 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2589 "zparser.c" /* yacc.c:1646 */ break; case 103: #line 595 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2595 "zparser.c" /* yacc.c:1646 */ break; case 105: #line 597 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2601 "zparser.c" /* yacc.c:1646 */ break; case 107: #line 599 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2607 "zparser.c" /* yacc.c:1646 */ break; case 109: #line 601 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2613 "zparser.c" /* yacc.c:1646 */ break; case 111: #line 603 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2619 "zparser.c" /* yacc.c:1646 */ break; case 113: #line 605 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2625 "zparser.c" /* yacc.c:1646 */ break; case 115: #line 607 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2631 "zparser.c" /* yacc.c:1646 */ break; case 117: #line 609 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2637 "zparser.c" /* yacc.c:1646 */ break; case 119: #line 611 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2643 "zparser.c" /* yacc.c:1646 */ break; case 121: #line 613 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2649 "zparser.c" /* yacc.c:1646 */ break; case 123: #line 615 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2655 "zparser.c" /* yacc.c:1646 */ break; case 125: #line 617 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2661 "zparser.c" /* yacc.c:1646 */ break; case 127: #line 619 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2667 "zparser.c" /* yacc.c:1646 */ break; case 129: #line 621 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2673 "zparser.c" /* yacc.c:1646 */ break; case 131: #line 623 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2679 "zparser.c" /* yacc.c:1646 */ break; case 133: #line 625 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2685 "zparser.c" /* yacc.c:1646 */ break; case 135: #line 627 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2691 "zparser.c" /* yacc.c:1646 */ break; case 138: #line 630 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2697 "zparser.c" /* yacc.c:1646 */ break; case 140: #line 632 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2703 "zparser.c" /* yacc.c:1646 */ break; case 141: #line 633 "zparser.y" /* yacc.c:1646 */ { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } } #line 2709 "zparser.c" /* yacc.c:1646 */ break; case 142: #line 634 "zparser.y" /* yacc.c:1646 */ { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2715 "zparser.c" /* yacc.c:1646 */ break; case 144: #line 636 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2721 "zparser.c" /* yacc.c:1646 */ break; case 146: #line 638 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2727 "zparser.c" /* yacc.c:1646 */ break; case 148: #line 640 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2733 "zparser.c" /* yacc.c:1646 */ break; case 150: #line 642 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2739 "zparser.c" /* yacc.c:1646 */ break; case 152: #line 644 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2745 "zparser.c" /* yacc.c:1646 */ break; case 154: #line 646 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2751 "zparser.c" /* yacc.c:1646 */ break; case 156: #line 648 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2757 "zparser.c" /* yacc.c:1646 */ break; case 158: #line 650 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2763 "zparser.c" /* yacc.c:1646 */ break; case 160: #line 652 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2769 "zparser.c" /* yacc.c:1646 */ break; case 162: #line 654 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2775 "zparser.c" /* yacc.c:1646 */ break; case 164: #line 656 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2781 "zparser.c" /* yacc.c:1646 */ break; case 166: #line 658 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2787 "zparser.c" /* yacc.c:1646 */ break; case 168: #line 660 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2793 "zparser.c" /* yacc.c:1646 */ break; case 170: #line 662 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2799 "zparser.c" /* yacc.c:1646 */ break; case 172: #line 664 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2805 "zparser.c" /* yacc.c:1646 */ break; case 174: #line 666 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2811 "zparser.c" /* yacc.c:1646 */ break; case 176: #line 668 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2817 "zparser.c" /* yacc.c:1646 */ break; case 178: #line 670 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2823 "zparser.c" /* yacc.c:1646 */ break; case 180: #line 672 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2829 "zparser.c" /* yacc.c:1646 */ break; case 182: #line 674 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2835 "zparser.c" /* yacc.c:1646 */ break; case 183: #line 675 "zparser.y" /* yacc.c:1646 */ { (yyval.type) = (yyvsp[-2].type); parse_unknown_rdata((yyvsp[-2].type), (yyvsp[0].unknown)); } #line 2841 "zparser.c" /* yacc.c:1646 */ break; case 184: #line 677 "zparser.y" /* yacc.c:1646 */ { zc_error_prev_line("unrecognized RR type '%s'", (yyvsp[-2].data).str); } #line 2849 "zparser.c" /* yacc.c:1646 */ break; case 185: #line 689 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_a(parser->region, (yyvsp[-1].data).str)); } #line 2857 "zparser.c" /* yacc.c:1646 */ break; case 186: #line 695 "zparser.y" /* yacc.c:1646 */ { /* convert a single dname record */ zadd_rdata_domain((yyvsp[-1].domain)); } #line 2866 "zparser.c" /* yacc.c:1646 */ break; case 187: #line 702 "zparser.y" /* yacc.c:1646 */ { /* convert the soa data */ zadd_rdata_domain((yyvsp[-13].domain)); /* prim. ns */ zadd_rdata_domain((yyvsp[-11].domain)); /* email */ zadd_rdata_wireformat(zparser_conv_serial(parser->region, (yyvsp[-9].data).str)); /* serial */ zadd_rdata_wireformat(zparser_conv_period(parser->region, (yyvsp[-7].data).str)); /* refresh */ zadd_rdata_wireformat(zparser_conv_period(parser->region, (yyvsp[-5].data).str)); /* retry */ zadd_rdata_wireformat(zparser_conv_period(parser->region, (yyvsp[-3].data).str)); /* expire */ zadd_rdata_wireformat(zparser_conv_period(parser->region, (yyvsp[-1].data).str)); /* minimum */ } #line 2881 "zparser.c" /* yacc.c:1646 */ break; case 188: #line 715 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_a(parser->region, (yyvsp[-5].data).str)); /* address */ zadd_rdata_wireformat(zparser_conv_services(parser->region, (yyvsp[-3].data).str, (yyvsp[-1].data).str)); /* protocol and services */ } #line 2890 "zparser.c" /* yacc.c:1646 */ break; case 189: #line 722 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-3].data).str, (yyvsp[-3].data).len)); /* CPU */ zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* OS*/ } #line 2899 "zparser.c" /* yacc.c:1646 */ break; case 190: #line 729 "zparser.y" /* yacc.c:1646 */ { /* convert a single dname record */ zadd_rdata_domain((yyvsp[-3].domain)); zadd_rdata_domain((yyvsp[-1].domain)); } #line 2909 "zparser.c" /* yacc.c:1646 */ break; case 191: #line 737 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* priority */ zadd_rdata_domain((yyvsp[-1].domain)); /* MX host */ } #line 2918 "zparser.c" /* yacc.c:1646 */ break; case 192: #line 744 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_txt_clean_wireformat(); } #line 2926 "zparser.c" /* yacc.c:1646 */ break; case 193: #line 751 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_domain((yyvsp[-3].domain)); /* mbox d-name */ zadd_rdata_domain((yyvsp[-1].domain)); /* txt d-name */ } #line 2935 "zparser.c" /* yacc.c:1646 */ break; case 194: #line 759 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* subtype */ zadd_rdata_domain((yyvsp[-1].domain)); /* domain name */ } #line 2944 "zparser.c" /* yacc.c:1646 */ break; case 195: #line 767 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* X.25 address. */ } #line 2952 "zparser.c" /* yacc.c:1646 */ break; case 196: #line 774 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* address */ } #line 2960 "zparser.c" /* yacc.c:1646 */ break; case 197: #line 778 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-3].data).str, (yyvsp[-3].data).len)); /* address */ zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* sub-address */ } #line 2969 "zparser.c" /* yacc.c:1646 */ break; case 198: #line 786 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_domain((yyvsp[-1].domain)); /* intermediate host */ } #line 2978 "zparser.c" /* yacc.c:1646 */ break; case 199: #line 794 "zparser.y" /* yacc.c:1646 */ { /* String must start with "0x" or "0X". */ if (strncasecmp((yyvsp[-1].data).str, "0x", 2) != 0) { zc_error_prev_line("NSAP rdata must start with '0x'"); } else { zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str + 2, (yyvsp[-1].data).len - 2)); /* NSAP */ } } #line 2991 "zparser.c" /* yacc.c:1646 */ break; case 200: #line 806 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-5].data).str)); /* preference */ zadd_rdata_domain((yyvsp[-3].domain)); /* MAP822 */ zadd_rdata_domain((yyvsp[-1].domain)); /* MAPX400 */ } #line 3001 "zparser.c" /* yacc.c:1646 */ break; case 201: #line 814 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, (yyvsp[-1].data).str)); /* IPv6 address */ } #line 3009 "zparser.c" /* yacc.c:1646 */ break; case 202: #line 820 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_loc(parser->region, (yyvsp[-1].data).str)); /* Location */ } #line 3017 "zparser.c" /* yacc.c:1646 */ break; case 203: #line 826 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_domain((yyvsp[-3].domain)); /* nxt name */ zadd_rdata_wireformat(zparser_conv_nxt(parser->region, nxtbits)); /* nxt bitlist */ memset(nxtbits, 0, sizeof(nxtbits)); } #line 3027 "zparser.c" /* yacc.c:1646 */ break; case 204: #line 834 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-7].data).str)); /* prio */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-5].data).str)); /* weight */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* port */ zadd_rdata_domain((yyvsp[-1].domain)); /* target name */ } #line 3038 "zparser.c" /* yacc.c:1646 */ break; case 205: #line 844 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-11].data).str)); /* order */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-9].data).str)); /* preference */ zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-7].data).str, (yyvsp[-7].data).len)); /* flags */ zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-5].data).str, (yyvsp[-5].data).len)); /* service */ zadd_rdata_wireformat(zparser_conv_text(parser->region, (yyvsp[-3].data).str, (yyvsp[-3].data).len)); /* regexp */ zadd_rdata_domain((yyvsp[-1].domain)); /* target name */ } #line 3051 "zparser.c" /* yacc.c:1646 */ break; case 206: #line 856 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_domain((yyvsp[-1].domain)); /* exchanger */ } #line 3060 "zparser.c" /* yacc.c:1646 */ break; case 207: #line 864 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_certificate_type(parser->region, (yyvsp[-7].data).str)); /* type */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-5].data).str)); /* key tag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, (yyvsp[-3].data).str)); /* algorithm */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); /* certificate or CRL */ } #line 3071 "zparser.c" /* yacc.c:1646 */ break; case 209: #line 877 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, (yyvsp[0].data).str)); } #line 3079 "zparser.c" /* yacc.c:1646 */ break; case 210: #line 881 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, (yyvsp[0].data).str)); } #line 3087 "zparser.c" /* yacc.c:1646 */ break; case 211: #line 887 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-7].data).str)); /* keytag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, (yyvsp[-5].data).str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-3].data).str)); /* type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* hash */ } #line 3098 "zparser.c" /* yacc.c:1646 */ break; case 212: #line 896 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-7].data).str)); /* keytag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, (yyvsp[-5].data).str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-3].data).str)); /* type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* hash */ } #line 3109 "zparser.c" /* yacc.c:1646 */ break; case 213: #line 905 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-5].data).str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-3].data).str)); /* fp type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* hash */ } #line 3119 "zparser.c" /* yacc.c:1646 */ break; case 214: #line 913 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); /* data blob */ } #line 3127 "zparser.c" /* yacc.c:1646 */ break; case 215: #line 919 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_rrtype(parser->region, (yyvsp[-17].data).str)); /* rr covered */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, (yyvsp[-15].data).str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-13].data).str)); /* # labels */ zadd_rdata_wireformat(zparser_conv_period(parser->region, (yyvsp[-11].data).str)); /* # orig TTL */ zadd_rdata_wireformat(zparser_conv_time(parser->region, (yyvsp[-9].data).str)); /* sig exp */ zadd_rdata_wireformat(zparser_conv_time(parser->region, (yyvsp[-7].data).str)); /* sig inc */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-5].data).str)); /* key id */ zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, (const uint8_t*) (yyvsp[-3].data).str,(yyvsp[-3].data).len)); /* sig name */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); /* sig data */ } #line 3144 "zparser.c" /* yacc.c:1646 */ break; case 216: #line 934 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, (const uint8_t*) (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* nsec name */ zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; } #line 3156 "zparser.c" /* yacc.c:1646 */ break; case 217: #line 944 "zparser.y" /* yacc.c:1646 */ { #ifdef NSEC3 nsec3_add_params((yyvsp[-9].data).str, (yyvsp[-7].data).str, (yyvsp[-5].data).str, (yyvsp[-3].data).str, (yyvsp[-3].data).len); zadd_rdata_wireformat(zparser_conv_b32(parser->region, (yyvsp[-1].data).str)); /* next hashed name */ zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; #else zc_error_prev_line("nsec3 not supported"); #endif /* NSEC3 */ } #line 3173 "zparser.c" /* yacc.c:1646 */ break; case 218: #line 959 "zparser.y" /* yacc.c:1646 */ { #ifdef NSEC3 nsec3_add_params((yyvsp[-7].data).str, (yyvsp[-5].data).str, (yyvsp[-3].data).str, (yyvsp[-1].data).str, (yyvsp[-1].data).len); #else zc_error_prev_line("nsec3 not supported"); #endif /* NSEC3 */ } #line 3185 "zparser.c" /* yacc.c:1646 */ break; case 219: #line 969 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-7].data).str)); /* usage */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-5].data).str)); /* selector */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-3].data).str)); /* matching type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* ca data */ } #line 3196 "zparser.c" /* yacc.c:1646 */ break; case 220: #line 978 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-7].data).str)); /* usage */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-5].data).str)); /* selector */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-3].data).str)); /* matching type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* ca data */ } #line 3207 "zparser.c" /* yacc.c:1646 */ break; case 221: #line 987 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-7].data).str)); /* flags */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-5].data).str)); /* proto */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, (yyvsp[-3].data).str)); /* alg */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); /* hash */ } #line 3218 "zparser.c" /* yacc.c:1646 */ break; case 222: #line 996 "zparser.y" /* yacc.c:1646 */ { const dname_type* name = 0; zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-6].data).str)); /* precedence */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-4].data).str)); /* gateway type */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-2].data).str)); /* algorithm */ switch(atoi((yyvsp[-4].data).str)) { case IPSECKEY_NOGATEWAY: zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 0)); break; case IPSECKEY_IP4: zadd_rdata_wireformat(zparser_conv_a(parser->region, (yyvsp[0].data).str)); break; case IPSECKEY_IP6: zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, (yyvsp[0].data).str)); break; case IPSECKEY_DNAME: /* convert and insert the dname */ if(strlen((yyvsp[0].data).str) == 0) zc_error_prev_line("IPSECKEY must specify gateway name"); if(!(name = dname_parse(parser->region, (yyvsp[0].data).str))) { zc_error_prev_line("IPSECKEY bad gateway dname %s", (yyvsp[0].data).str); break; } if((yyvsp[0].data).str[strlen((yyvsp[0].data).str)-1] != '.') { if(parser->origin == error_domain) { zc_error("cannot concatenate origin to domain name, because origin failed to parse"); break; } name = dname_concatenate(parser->rr_region, name, domain_dname(parser->origin)); } zadd_rdata_wireformat(alloc_rdata_init(parser->region, dname_name(name), name->name_size)); break; default: zc_error_prev_line("unknown IPSECKEY gateway type"); } } #line 3261 "zparser.c" /* yacc.c:1646 */ break; case 223: #line 1037 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); /* public key */ } #line 3269 "zparser.c" /* yacc.c:1646 */ break; case 225: #line 1045 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, (yyvsp[-1].data).str)); /* NodeID */ } #line 3278 "zparser.c" /* yacc.c:1646 */ break; case 226: #line 1052 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_wireformat(zparser_conv_a(parser->region, (yyvsp[-1].data).str)); /* Locator32 */ } #line 3287 "zparser.c" /* yacc.c:1646 */ break; case 227: #line 1059 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, (yyvsp[-1].data).str)); /* Locator64 */ } #line 3296 "zparser.c" /* yacc.c:1646 */ break; case 228: #line 1066 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* preference */ zadd_rdata_domain((yyvsp[-1].domain)); /* FQDN */ } #line 3305 "zparser.c" /* yacc.c:1646 */ break; case 229: #line 1073 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_eui(parser->region, (yyvsp[-1].data).str, 48)); } #line 3313 "zparser.c" /* yacc.c:1646 */ break; case 230: #line 1079 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_eui(parser->region, (yyvsp[-1].data).str, 64)); } #line 3321 "zparser.c" /* yacc.c:1646 */ break; case 231: #line 1086 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-5].data).str)); /* priority */ zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-3].data).str)); /* weight */ zadd_rdata_wireformat(zparser_conv_long_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* target */ } #line 3331 "zparser.c" /* yacc.c:1646 */ break; case 232: #line 1095 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_byte(parser->region, (yyvsp[-5].data).str)); /* Flags */ zadd_rdata_wireformat(zparser_conv_tag(parser->region, (yyvsp[-3].data).str, (yyvsp[-3].data).len)); /* Tag */ zadd_rdata_wireformat(zparser_conv_long_text(parser->region, (yyvsp[-1].data).str, (yyvsp[-1].data).len)); /* Value */ } #line 3341 "zparser.c" /* yacc.c:1646 */ break; case 233: #line 1104 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_b64(parser->region, (yyvsp[-1].data).str)); } #line 3349 "zparser.c" /* yacc.c:1646 */ break; case 234: #line 1111 "zparser.y" /* yacc.c:1646 */ { zadd_rdata_wireformat(zparser_conv_serial(parser->region, (yyvsp[-3].data).str)); zadd_rdata_wireformat(zparser_conv_short(parser->region, (yyvsp[-1].data).str)); zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; } #line 3361 "zparser.c" /* yacc.c:1646 */ break; case 235: #line 1121 "zparser.y" /* yacc.c:1646 */ { /* $2 is the number of octets, currently ignored */ (yyval.unknown) = zparser_conv_hex(parser->rr_region, (yyvsp[-1].data).str, (yyvsp[-1].data).len); } #line 3371 "zparser.c" /* yacc.c:1646 */ break; case 236: #line 1127 "zparser.y" /* yacc.c:1646 */ { (yyval.unknown) = zparser_conv_hex(parser->rr_region, "", 0); } #line 3379 "zparser.c" /* yacc.c:1646 */ break; case 237: #line 1131 "zparser.y" /* yacc.c:1646 */ { (yyval.unknown) = zparser_conv_hex(parser->rr_region, "", 0); } #line 3387 "zparser.c" /* yacc.c:1646 */ break; #line 3391 "zparser.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 1135 "zparser.y" /* yacc.c:1906 */ int yywrap(void) { return 1; } /* * Create the parser. */ zparser_type * zparser_create(region_type *region, region_type *rr_region, namedb_type *db) { zparser_type *result; result = (zparser_type *) region_alloc(region, sizeof(zparser_type)); result->region = region; result->rr_region = rr_region; result->db = db; result->filename = NULL; result->current_zone = NULL; result->origin = NULL; result->prev_dname = NULL; result->default_apex = NULL; result->temporary_rdatas = (rdata_atom_type *) region_alloc_array( result->region, MAXRDATALEN, sizeof(rdata_atom_type)); return result; } /* * Initialize the parser for a new zone file. */ void zparser_init(const char *filename, uint32_t ttl, uint16_t klass, const dname_type *origin) { memset(nxtbits, 0, sizeof(nxtbits)); memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; parser->default_ttl = ttl; parser->default_class = klass; parser->current_zone = NULL; parser->origin = domain_table_insert(parser->db->domains, origin); parser->prev_dname = parser->origin; parser->default_apex = parser->origin; parser->error_occurred = 0; parser->errors = 0; parser->line = 1; parser->filename = filename; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; } void yyerror(const char *message) { zc_error("%s", message); } static void error_va_list(unsigned line, const char *fmt, va_list args) { if (parser->filename) { char message[MAXSYSLOGMSGLEN]; vsnprintf(message, sizeof(message), fmt, args); log_msg(LOG_ERR, "%s:%u: %s", parser->filename, line, message); } else log_vmsg(LOG_ERR, fmt, args); ++parser->errors; parser->error_occurred = 1; } /* the line counting sux, to say the least * with this grose hack we try do give sane * numbers back */ void zc_error_prev_line(const char *fmt, ...) { va_list args; va_start(args, fmt); error_va_list(parser->line - 1, fmt, args); va_end(args); } void zc_error(const char *fmt, ...) { /* send an error message to stderr */ va_list args; va_start(args, fmt); error_va_list(parser->line, fmt, args); va_end(args); } static void warning_va_list(unsigned line, const char *fmt, va_list args) { if (parser->filename) { char m[MAXSYSLOGMSGLEN]; vsnprintf(m, sizeof(m), fmt, args); log_msg(LOG_WARNING, "%s:%u: %s", parser->filename, line, m); } else log_vmsg(LOG_WARNING, fmt, args); } void zc_warning_prev_line(const char *fmt, ...) { va_list args; va_start(args, fmt); warning_va_list(parser->line - 1, fmt, args); va_end(args); } void zc_warning(const char *fmt, ... ) { va_list args; va_start(args, fmt); warning_va_list(parser->line, fmt, args); va_end(args); } #ifdef NSEC3 static void nsec3_add_params(const char* hashalgo_str, const char* flag_str, const char* iter_str, const char* salt_str, int salt_len) { zadd_rdata_wireformat(zparser_conv_byte(parser->region, hashalgo_str)); zadd_rdata_wireformat(zparser_conv_byte(parser->region, flag_str)); zadd_rdata_wireformat(zparser_conv_short(parser->region, iter_str)); /* salt */ if(strcmp(salt_str, "-") != 0) zadd_rdata_wireformat(zparser_conv_hex_length(parser->region, salt_str, salt_len)); else zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 1)); } #endif /* NSEC3 */ nsd-4.1.26/xfrd.c0000664000175000017500000023234613355344112013150 0ustar wouterwouter/* * xfrd.c - XFR (transfer) Daemon source file. Coordinates SOA updates. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "xfrd.h" #include "xfrd-tcp.h" #include "xfrd-disk.h" #include "xfrd-notify.h" #include "options.h" #include "util.h" #include "netio.h" #include "region-allocator.h" #include "nsd.h" #include "packet.h" #include "rdata.h" #include "difffile.h" #include "ipc.h" #include "remote.h" #include "rrl.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif #ifdef HAVE_SYSTEMD #include #endif #define XFRD_UDP_TIMEOUT 10 /* seconds, before a udp request times out */ #define XFRD_NO_IXFR_CACHE 172800 /* 48h before retrying ixfr's after notimpl */ #define XFRD_LOWERBOUND_REFRESH 1 /* seconds, smallest refresh timeout */ #define XFRD_LOWERBOUND_RETRY 1 /* seconds, smallest retry timeout */ #define XFRD_MAX_ROUNDS 1 /* max number of rounds along the masters */ #define XFRD_TSIG_MAX_UNSIGNED 103 /* max number of packets without tsig in a tcp stream. */ /* rfc recommends 100, +3 for offbyone errors/interoperability. */ #define XFRD_CHILD_REAP_TIMEOUT 60 /* seconds to wakeup and reap lost children */ /* these are reload processes that SIGCHILDed but the signal * was lost, and need waitpid to remove their process entry. */ /* the daemon state */ xfrd_state_type* xfrd = 0; /* main xfrd loop */ static void xfrd_main(void); /* shut down xfrd, close sockets. */ static void xfrd_shutdown(void); /* delete pending task xfr files in tmp */ static void xfrd_clean_pending_tasks(struct nsd* nsd, udb_base* u); /* create zone rbtree at start */ static void xfrd_init_zones(void); /* initial handshake with SOAINFO from main and send expire to main */ static void xfrd_receive_soa(int socket, int shortsoa); /* handle incoming notification message. soa can be NULL. true if transfer needed. */ static int xfrd_handle_incoming_notify(xfrd_zone_type* zone, xfrd_soa_type* soa); /* call with buffer just after the soa dname. returns 0 on error. */ static int xfrd_parse_soa_info(buffer_type* packet, xfrd_soa_type* soa); /* set the zone state to a new state (takes care of expiry messages) */ static void xfrd_set_zone_state(xfrd_zone_type* zone, enum xfrd_zone_state new_zone_state); /* set timer for retry amount (depends on zone_state) */ static void xfrd_set_timer_retry(xfrd_zone_type* zone); /* set timer for refresh timeout (depends on zone_state) */ static void xfrd_set_timer_refresh(xfrd_zone_type* zone); /* set reload timeout */ static void xfrd_set_reload_timeout(void); /* handle reload timeout */ static void xfrd_handle_reload(int fd, short event, void* arg); /* handle child timeout */ static void xfrd_handle_child_timer(int fd, short event, void* arg); /* send ixfr request, returns fd of connection to read on */ static int xfrd_send_ixfr_request_udp(xfrd_zone_type* zone); /* obtain udp socket slot */ static void xfrd_udp_obtain(xfrd_zone_type* zone); /* read data via udp */ static void xfrd_udp_read(xfrd_zone_type* zone); /* find master by notify number */ static int find_same_master_notify(xfrd_zone_type* zone, int acl_num_nfy); /* set the write timer to activate */ static void xfrd_write_timer_set(void); static void xfrd_signal_callback(int sig, short event, void* ATTR_UNUSED(arg)) { if(!(event & EV_SIGNAL)) return; sig_handler(sig); } static struct event* xfrd_sig_evs[10]; static int xfrd_sig_num = 0; static void xfrd_sigsetup(int sig) { struct event *ev = xalloc_zero(sizeof(*ev)); assert(xfrd_sig_num <= (int)(sizeof(xfrd_sig_evs)/sizeof(ev))); xfrd_sig_evs[xfrd_sig_num++] = ev; signal_set(ev, sig, xfrd_signal_callback, NULL); if(event_base_set(xfrd->event_base, ev) != 0) { log_msg(LOG_ERR, "xfrd sig handler: event_base_set failed"); } if(signal_add(ev, NULL) != 0) { log_msg(LOG_ERR, "xfrd sig handler: signal_add failed"); } } void xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, pid_t nsd_pid) { region_type* region; assert(xfrd == 0); /* to setup signalhandling */ nsd->server_kind = NSD_SERVER_MAIN; region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); xfrd = (xfrd_state_type*)region_alloc(region, sizeof(xfrd_state_type)); memset(xfrd, 0, sizeof(xfrd_state_type)); xfrd->region = region; xfrd->xfrd_start_time = time(0); xfrd->event_base = nsd_child_event_base(); if(!xfrd->event_base) { log_msg(LOG_ERR, "xfrd: cannot create event base"); exit(1); } xfrd->nsd = nsd; xfrd->packet = buffer_create(xfrd->region, QIOBUFSZ); xfrd->udp_waiting_first = NULL; xfrd->udp_waiting_last = NULL; xfrd->udp_use_num = 0; xfrd->got_time = 0; xfrd->xfrfilenumber = 0; #ifdef USE_ZONE_STATS xfrd->zonestat_safe = nsd->zonestatdesired; #endif xfrd->activated_first = NULL; xfrd->ipc_pass = buffer_create(xfrd->region, QIOBUFSZ); xfrd->last_task = region_alloc(xfrd->region, sizeof(*xfrd->last_task)); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); assert(shortsoa || udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0); xfrd->reload_handler.ev_fd = -1; xfrd->reload_added = 0; xfrd->reload_timeout.tv_sec = 0; xfrd->reload_cmd_last_sent = xfrd->xfrd_start_time; xfrd->can_send_reload = !reload_active; xfrd->reload_pid = nsd_pid; xfrd->child_timer_added = 0; xfrd->ipc_send_blocked = 0; event_set(&xfrd->ipc_handler, socket, EV_PERSIST|EV_READ, xfrd_handle_ipc, xfrd); if(event_base_set(xfrd->event_base, &xfrd->ipc_handler) != 0) log_msg(LOG_ERR, "xfrd ipc handler: event_base_set failed"); if(event_add(&xfrd->ipc_handler, NULL) != 0) log_msg(LOG_ERR, "xfrd ipc handler: event_add failed"); xfrd->ipc_handler_flags = EV_PERSIST|EV_READ; xfrd->ipc_conn = xfrd_tcp_create(xfrd->region, QIOBUFSZ); /* not reading using ipc_conn yet */ xfrd->ipc_conn->is_reading = 0; xfrd->ipc_conn->fd = socket; xfrd->need_to_send_reload = 0; xfrd->need_to_send_shutdown = 0; xfrd->need_to_send_stats = 0; xfrd->write_zonefile_needed = 0; if(nsd->options->zonefiles_write) xfrd_write_timer_set(); xfrd->notify_waiting_first = NULL; xfrd->notify_waiting_last = NULL; xfrd->notify_udp_num = 0; #ifdef HAVE_SSL daemon_remote_attach(xfrd->nsd->rc, xfrd); #endif xfrd->tcp_set = xfrd_tcp_set_create(xfrd->region); xfrd->tcp_set->tcp_timeout = nsd->tcp_timeout; #ifndef HAVE_ARC4RANDOM srandom((unsigned long) getpid() * (unsigned long) time(NULL)); #endif DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd pre-startup")); xfrd_init_zones(); xfrd_receive_soa(socket, shortsoa); if(nsd->options->xfrdfile != NULL && nsd->options->xfrdfile[0]!=0) xfrd_read_state(xfrd); /* did we get killed before startup was successful? */ if(nsd->signal_hint_shutdown) { kill(nsd_pid, SIGTERM); xfrd_shutdown(); return; } /* init libevent signals now, so that in the previous init scripts * the normal sighandler is called, and can set nsd->signal_hint.. * these are also looked at in sig_process before we run the main loop*/ xfrd_sigsetup(SIGHUP); xfrd_sigsetup(SIGTERM); xfrd_sigsetup(SIGQUIT); xfrd_sigsetup(SIGCHLD); xfrd_sigsetup(SIGALRM); xfrd_sigsetup(SIGILL); xfrd_sigsetup(SIGUSR1); xfrd_sigsetup(SIGINT); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd startup")); #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif xfrd_main(); } static void xfrd_process_activated(void) { xfrd_zone_type* zone; while((zone = xfrd->activated_first)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s activation", zone->apex_str)); /* pop zone from activated list */ xfrd->activated_first = zone->activated_next; if(zone->activated_next) zone->activated_next->activated_prev = NULL; zone->is_activated = 0; /* run it : no events, specifically not the TIMEOUT event, * so that running zone transfers are not interrupted */ xfrd_handle_zone(zone->zone_handler.ev_fd, 0, zone); } } static void xfrd_sig_process(void) { int status; pid_t child_pid; if(xfrd->nsd->signal_hint_quit || xfrd->nsd->signal_hint_shutdown) { xfrd->nsd->signal_hint_quit = 0; xfrd->nsd->signal_hint_shutdown = 0; xfrd->need_to_send_shutdown = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } else if(xfrd->nsd->signal_hint_reload_hup) { log_msg(LOG_WARNING, "SIGHUP received, reloading..."); xfrd->nsd->signal_hint_reload_hup = 0; if(xfrd->nsd->options->zonefiles_check) { task_new_check_zonefiles(xfrd->nsd->task[ xfrd->nsd->mytask], xfrd->last_task, NULL); } xfrd_set_reload_now(xfrd); } else if(xfrd->nsd->signal_hint_statsusr) { xfrd->nsd->signal_hint_statsusr = 0; xfrd->need_to_send_stats = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } /* collect children that exited. */ xfrd->nsd->signal_hint_child = 0; while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { if(status != 0) { log_msg(LOG_ERR, "process %d exited with status %d", (int)child_pid, status); } } if(!xfrd->child_timer_added) { struct timeval tv; tv.tv_sec = XFRD_CHILD_REAP_TIMEOUT; tv.tv_usec = 0; event_set(&xfrd->child_timer, -1, EV_TIMEOUT, xfrd_handle_child_timer, xfrd); if(event_base_set(xfrd->event_base, &xfrd->child_timer) != 0) log_msg(LOG_ERR, "xfrd child timer: event_base_set failed"); if(event_add(&xfrd->child_timer, &tv) != 0) log_msg(LOG_ERR, "xfrd child timer: event_add failed"); xfrd->child_timer_added = 1; } } static void xfrd_main(void) { /* we may have signals from the startup period, process them */ xfrd_sig_process(); xfrd->shutdown = 0; while(!xfrd->shutdown) { /* process activated zones before blocking in select again */ xfrd_process_activated(); /* dispatch may block for a longer period, so current is gone */ xfrd->got_time = 0; if(event_base_loop(xfrd->event_base, EVLOOP_ONCE) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "xfrd dispatch failed: %s", strerror(errno)); } } xfrd_sig_process(); } xfrd_shutdown(); } static void xfrd_shutdown() { xfrd_zone_type* zone; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown")); #ifdef HAVE_SYSTEMD sd_notify(0, "STOPPING=1"); #endif event_del(&xfrd->ipc_handler); close(xfrd->ipc_handler.ev_fd); /* notifies parent we stop */ zone_list_close(nsd.options); if(xfrd->nsd->options->xfrdfile != NULL && xfrd->nsd->options->xfrdfile[0]!=0) xfrd_write_state(xfrd); if(xfrd->reload_added) { event_del(&xfrd->reload_handler); xfrd->reload_added = 0; } if(xfrd->child_timer_added) { event_del(&xfrd->child_timer); xfrd->child_timer_added = 0; } if(xfrd->nsd->options->zonefiles_write) { event_del(&xfrd->write_timer); } #ifdef HAVE_SSL daemon_remote_close(xfrd->nsd->rc); /* close sockets of rc */ #endif /* close sockets */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->event_added) { event_del(&zone->zone_handler); if(zone->zone_handler.ev_fd != -1) { close(zone->zone_handler.ev_fd); zone->zone_handler.ev_fd = -1; } zone->event_added = 0; } } close_notify_fds(xfrd->notify_zones); /* wait for server parent (if necessary) */ if(xfrd->reload_pid != -1) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd wait for servermain %d", (int)xfrd->reload_pid)); while(1) { if(waitpid(xfrd->reload_pid, NULL, 0) == -1) { if(errno == EINTR) continue; if(errno == ECHILD) break; log_msg(LOG_ERR, "xfrd: waitpid(%d): %s", (int)xfrd->reload_pid, strerror(errno)); } break; } } /* if we are killed past this point this is not a problem, * some files left in /tmp are cleaned by the OS, but it is neater * to clean them out */ /* unlink xfr files for running transfers */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->msg_seq_nr) xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); } /* unlink xfr files in not-yet-done task file */ xfrd_clean_pending_tasks(xfrd->nsd, xfrd->nsd->task[xfrd->nsd->mytask]); xfrd_del_tempdir(xfrd->nsd); #ifdef HAVE_SSL daemon_remote_delete(xfrd->nsd->rc); /* ssl-delete secret keys */ #endif #ifdef USE_DNSTAP dt_collector_close(nsd.dt_collector, &nsd); #endif /* process-exit cleans up memory used by xfrd process */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown complete")); #ifdef MEMCLEAN /* OS collects memory pages */ if(xfrd->zones) { xfrd_zone_type* z; RBTREE_FOR(z, xfrd_zone_type*, xfrd->zones) { tsig_delete_record(&z->tsig, NULL); } } if(xfrd->notify_zones) { struct notify_zone* n; RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones) { tsig_delete_record(&n->notify_tsig, NULL); } } if(xfrd_sig_num > 0) { int i; for(i=0; ievent_base); region_destroy(xfrd->region); nsd_options_destroy(nsd.options); region_destroy(nsd.region); log_finalize(); #endif exit(0); } static void xfrd_clean_pending_tasks(struct nsd* nsd, udb_base* u) { udb_ptr t; udb_ptr_new(&t, u, udb_base_get_userdata(u)); /* no dealloc of entries, we delete the entire file when done */ while(!udb_ptr_is_null(&t)) { if(TASKLIST(&t)->task_type == task_apply_xfr) { xfrd_unlink_xfrfile(nsd, TASKLIST(&t)->yesno); } udb_ptr_set_rptr(&t, u, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, u); } void xfrd_init_slave_zone(xfrd_state_type* xfrd, struct zone_options* zone_opt) { xfrd_zone_type *xzone; xzone = (xfrd_zone_type*)region_alloc(xfrd->region, sizeof(xfrd_zone_type)); memset(xzone, 0, sizeof(xfrd_zone_type)); xzone->apex = zone_opt->node.key; xzone->apex_str = zone_opt->name; xzone->state = xfrd_zone_refreshing; xzone->zone_options = zone_opt; /* first retry will use first master */ xzone->master = xzone->zone_options->pattern->request_xfr; xzone->master_num = 0; xzone->next_master = 0; xzone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; xzone->soa_nsd_acquired = 0; xzone->soa_disk_acquired = 0; xzone->soa_notified_acquired = 0; /* [0]=1, [1]=0; "." domain name */ xzone->soa_nsd.prim_ns[0] = 1; xzone->soa_nsd.email[0] = 1; xzone->soa_disk.prim_ns[0]=1; xzone->soa_disk.email[0]=1; xzone->soa_notified.prim_ns[0]=1; xzone->soa_notified.email[0]=1; xzone->zone_handler.ev_fd = -1; xzone->zone_handler_flags = 0; xzone->event_added = 0; xzone->tcp_conn = -1; xzone->tcp_waiting = 0; xzone->udp_waiting = 0; xzone->is_activated = 0; xzone->multi_master_first_master = -1; xzone->multi_master_update_check = -1; tsig_create_record_custom(&xzone->tsig, NULL, 0, 0, 4); /* set refreshing anyway, if we have data it may be old */ xfrd_set_refresh_now(xzone); xzone->node.key = xzone->apex; rbtree_insert(xfrd->zones, (rbnode_type*)xzone); } static void xfrd_init_zones() { struct zone_options *zone_opt; assert(xfrd->zones == 0); xfrd->zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); xfrd->notify_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); RBTREE_FOR(zone_opt, struct zone_options*, xfrd->nsd->options->zone_options) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: adding %s zone", zone_opt->name)); init_notify_send(xfrd->notify_zones, xfrd->region, zone_opt); if(!zone_is_slave(zone_opt)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, " "master zone has no outgoing xfr requests", zone_opt->name)); continue; } xfrd_init_slave_zone(xfrd, zone_opt); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: started server %d " "secondary zones", (int)xfrd->zones->count)); } static void xfrd_process_soa_info_task(struct task_list_d* task) { xfrd_soa_type soa; xfrd_soa_type* soa_ptr = &soa; xfrd_zone_type* zone; DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: process SOAINFO %s", dname_to_string(task->zname, 0))); zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, task->zname); if(task->size <= sizeof(struct task_list_d)+dname_total_size( task->zname)+sizeof(uint32_t)*6 + sizeof(uint8_t)*2) { /* NSD has zone without any info */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s lost zone", dname_to_string(task->zname,0))); soa_ptr = NULL; } else { uint8_t* p = (uint8_t*)task->zname + dname_total_size( task->zname); /* read the soa info */ memset(&soa, 0, sizeof(soa)); /* left out type, klass, count for speed */ soa.type = htons(TYPE_SOA); soa.klass = htons(CLASS_IN); memmove(&soa.ttl, p, sizeof(uint32_t)); p += sizeof(uint32_t); soa.rdata_count = htons(7); memmove(soa.prim_ns, p, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(soa.prim_ns+1, p, soa.prim_ns[0]); p += soa.prim_ns[0]; memmove(soa.email, p, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(soa.email+1, p, soa.email[0]); p += soa.email[0]; memmove(&soa.serial, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.refresh, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.retry, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.expire, p, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(&soa.minimum, p, sizeof(uint32_t)); /* p += sizeof(uint32_t); if we wanted to read further */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s %u", dname_to_string(task->zname,0), (unsigned)ntohl(soa.serial))); } if(!zone) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: zone %s master zone updated", dname_to_string(task->zname,0))); notify_handle_master_zone_soainfo(xfrd->notify_zones, task->zname, soa_ptr); return; } xfrd_handle_incoming_soa(zone, soa_ptr, xfrd_time()); } static void xfrd_receive_soa(int socket, int shortsoa) { sig_atomic_t cmd; struct udb_base* xtask = xfrd->nsd->task[xfrd->nsd->mytask]; udb_ptr last_task, t; xfrd_zone_type* zone; if(!shortsoa) { /* put all expired zones into mytask */ udb_ptr_init(&last_task, xtask); RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->state == xfrd_zone_expired) { task_new_expire(xtask, &last_task, zone->apex, 1); } } udb_ptr_unlink(&last_task, xtask); /* send RELOAD to main to give it this tasklist */ task_process_sync(xtask); cmd = NSD_RELOAD; if(!write_socket(socket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending reload xfrdtomain: %s", strerror(errno)); } } /* receive RELOAD_DONE to get SOAINFO tasklist */ if(block_read(&nsd, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD_DONE) { if(nsd.signal_hint_shutdown) return; log_msg(LOG_ERR, "did not get start signal from main"); exit(1); } if(block_read(NULL, socket, &xfrd->reload_pid, sizeof(pid_t), -1) != sizeof(pid_t)) { log_msg(LOG_ERR, "xfrd cannot get reload_pid"); } /* process tasklist (SOAINFO data) */ udb_ptr_unlink(xfrd->last_task, xtask); /* if shortsoa: then use my own taskdb that nsdparent filled */ if(!shortsoa) xfrd->nsd->mytask = 1 - xfrd->nsd->mytask; xtask = xfrd->nsd->task[xfrd->nsd->mytask]; task_remap(xtask); udb_ptr_new(&t, xtask, udb_base_get_userdata(xtask)); while(!udb_ptr_is_null(&t)) { xfrd_process_soa_info_task(TASKLIST(&t)); udb_ptr_set_rptr(&t, xtask, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, xtask); task_clear(xtask); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); if(!shortsoa) { /* receive RELOAD_DONE that signals the other tasklist is * empty, and thus xfrd can operate (can call reload and swap * to the other, empty, tasklist) */ if(block_read(NULL, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD_DONE) { log_msg(LOG_ERR, "did not get start signal 2 from " "main"); exit(1); } } else { /* for shortsoa version, do expire later */ /* if expire notifications, put in my task and * schedule a reload to make sure they are processed */ RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { if(zone->state == xfrd_zone_expired) { xfrd_send_expire_notification(zone); } } } } void xfrd_reopen_logfile(void) { if (xfrd->nsd->file_rotation_ok) log_reopen(xfrd->nsd->log_filename, 0); } void xfrd_deactivate_zone(xfrd_zone_type* z) { if(z->is_activated) { /* delete from activated list */ if(z->activated_prev) z->activated_prev->activated_next = z->activated_next; else xfrd->activated_first = z->activated_next; if(z->activated_next) z->activated_next->activated_prev = z->activated_prev; z->is_activated = 0; } } void xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname) { xfrd_zone_type* z = (xfrd_zone_type*)rbtree_delete(xfrd->zones, dname); if(!z) return; /* io */ if(z->tcp_waiting) { /* delete from tcp waiting list */ if(z->tcp_waiting_prev) z->tcp_waiting_prev->tcp_waiting_next = z->tcp_waiting_next; else xfrd->tcp_set->tcp_waiting_first = z->tcp_waiting_next; if(z->tcp_waiting_next) z->tcp_waiting_next->tcp_waiting_prev = z->tcp_waiting_prev; else xfrd->tcp_set->tcp_waiting_last = z->tcp_waiting_prev; z->tcp_waiting = 0; } if(z->udp_waiting) { /* delete from udp waiting list */ if(z->udp_waiting_prev) z->udp_waiting_prev->udp_waiting_next = z->udp_waiting_next; else xfrd->udp_waiting_first = z->udp_waiting_next; if(z->udp_waiting_next) z->udp_waiting_next->udp_waiting_prev = z->udp_waiting_prev; else xfrd->udp_waiting_last = z->udp_waiting_prev; z->udp_waiting = 0; } xfrd_deactivate_zone(z); if(z->tcp_conn != -1) { xfrd_tcp_release(xfrd->tcp_set, z); } else if(z->zone_handler.ev_fd != -1 && z->event_added) { xfrd_udp_release(z); } else if(z->event_added) event_del(&z->zone_handler); if(z->msg_seq_nr) xfrd_unlink_xfrfile(xfrd->nsd, z->xfrfilenumber); /* tsig */ tsig_delete_record(&z->tsig, NULL); /* z->dname is recycled when the zone_options is removed */ region_recycle(xfrd->region, z, sizeof(*z)); } void xfrd_free_namedb(struct nsd* nsd) { namedb_close_udb(nsd->db); namedb_close(nsd->db); nsd->db = 0; } static void xfrd_set_timer_refresh(xfrd_zone_type* zone) { time_t set_refresh; time_t set_expire; time_t set_min; time_t set; if(zone->soa_disk_acquired == 0 || zone->state != xfrd_zone_ok) { xfrd_set_timer_retry(zone); return; } /* refresh or expire timeout, whichever is earlier */ set_refresh = ntohl(zone->soa_disk.refresh); if (set_refresh > (time_t)zone->zone_options->pattern->max_refresh_time) set_refresh = zone->zone_options->pattern->max_refresh_time; else if (set_refresh < (time_t)zone->zone_options->pattern->min_refresh_time) set_refresh = zone->zone_options->pattern->min_refresh_time; set_refresh += zone->soa_disk_acquired; set_expire = zone->soa_disk_acquired + ntohl(zone->soa_disk.expire); if(set_refresh < set_expire) set = set_refresh; else set = set_expire; set_min = zone->soa_disk_acquired + XFRD_LOWERBOUND_REFRESH; if(set < set_min) set = set_min; if(set < xfrd_time()) set = 0; else set -= xfrd_time(); xfrd_set_timer(zone, set); } static void xfrd_set_timer_retry(xfrd_zone_type* zone) { time_t set_retry; int mult; /* perform exponential backoff in all the cases */ if(zone->fresh_xfr_timeout == 0) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; else { /* exponential backoff - some master data in zones is paid-for but non-working, and will not get fixed. */ zone->fresh_xfr_timeout *= 2; if(zone->fresh_xfr_timeout > XFRD_TRANSFER_TIMEOUT_MAX) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_MAX; } /* exponential backoff multiplier, starts at 1, backs off */ mult = zone->fresh_xfr_timeout / XFRD_TRANSFER_TIMEOUT_START; if(mult == 0) mult = 1; /* set timer for next retry or expire timeout if earlier. */ if(zone->soa_disk_acquired == 0) { /* if no information, use reasonable timeout */ #ifdef HAVE_ARC4RANDOM_UNIFORM xfrd_set_timer(zone, zone->fresh_xfr_timeout + arc4random_uniform(zone->fresh_xfr_timeout)); #elif HAVE_ARC4RANDOM xfrd_set_timer(zone, zone->fresh_xfr_timeout + arc4random() % zone->fresh_xfr_timeout); #else xfrd_set_timer(zone, zone->fresh_xfr_timeout + random()%zone->fresh_xfr_timeout); #endif } else if(zone->state == xfrd_zone_expired || xfrd_time() + (time_t)ntohl(zone->soa_disk.retry)*mult < zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.expire)) { set_retry = ntohl(zone->soa_disk.retry); set_retry *= mult; if(set_retry > (time_t)zone->zone_options->pattern->max_retry_time) set_retry = zone->zone_options->pattern->max_retry_time; 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; xfrd_set_timer(zone, set_retry); } else { set_retry = ntohl(zone->soa_disk.expire); if(set_retry < XFRD_LOWERBOUND_RETRY) xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY); else { if(zone->soa_disk_acquired + set_retry < xfrd_time()) xfrd_set_timer(zone, XFRD_LOWERBOUND_RETRY); else xfrd_set_timer(zone, zone->soa_disk_acquired + set_retry - xfrd_time()); } } } void xfrd_handle_zone(int ATTR_UNUSED(fd), short event, void* arg) { xfrd_zone_type* zone = (xfrd_zone_type*)arg; if(zone->tcp_conn != -1) { if(event == 0) /* activated, but already in TCP, nothing to do*/ return; /* busy in tcp transaction: an internal error */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s event tcp", zone->apex_str)); xfrd_tcp_release(xfrd->tcp_set, zone); /* continue to retry; as if a timeout happened */ event = EV_TIMEOUT; } if((event & EV_READ)) { /* busy in udp transaction */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s event udp read", zone->apex_str)); xfrd_udp_read(zone); return; } /* timeout */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s timeout", zone->apex_str)); if(zone->zone_handler.ev_fd != -1 && zone->event_added && (event & EV_TIMEOUT)) { assert(zone->tcp_conn == -1); xfrd_udp_release(zone); } if(zone->tcp_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s skips retry, TCP connections full", zone->apex_str)); xfrd_unset_timer(zone); return; } if(zone->udp_waiting) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s skips retry, UDP connections full", zone->apex_str)); xfrd_unset_timer(zone); return; } if(zone->soa_disk_acquired) { if (zone->state != xfrd_zone_expired && xfrd_time() >= zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.expire)) { /* zone expired */ log_msg(LOG_ERR, "xfrd: zone %s has expired", zone->apex_str); xfrd_set_zone_state(zone, xfrd_zone_expired); } else if(zone->state == xfrd_zone_ok && xfrd_time() >= zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.refresh)) { /* zone goes to refreshing state. */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is refreshing", zone->apex_str)); xfrd_set_zone_state(zone, xfrd_zone_refreshing); } } /* only make a new request if no request is running (UDPorTCP) */ if(zone->zone_handler.ev_fd == -1 && zone->tcp_conn == -1) { /* make a new request */ xfrd_make_request(zone); } } void xfrd_make_request(xfrd_zone_type* zone) { if(zone->next_master != -1) { /* we are told to use this next master */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s use master %i", zone->apex_str, zone->next_master)); zone->master_num = zone->next_master; zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); /* if there is no next master, fallback to use the first one */ if(!zone->master) { zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; } /* fallback to cycle master */ zone->next_master = -1; zone->round_num = 0; /* fresh set of retries after notify */ } else { /* cycle master */ if(zone->round_num != -1 && zone->master && zone->master->next) { /* try the next master */ zone->master = zone->master->next; zone->master_num++; } else { /* start a new round */ zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; zone->round_num++; } if(zone->round_num >= XFRD_MAX_ROUNDS) { /* tried all servers that many times, wait */ zone->round_num = -1; xfrd_set_timer_retry(zone); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s makereq wait_retry, rd %d mr %d nx %d", zone->apex_str, zone->round_num, zone->master_num, zone->next_master)); zone->multi_master_first_master = -1; return; } } /* multi-master-check */ if(zone->zone_options->pattern->multi_master_check) { if(zone->multi_master_first_master == zone->master_num && zone->round_num > 0 && zone->state != xfrd_zone_expired) { /* tried all servers and update zone */ if(zone->multi_master_update_check >= 0) { VERBOSITY(2, (LOG_INFO, "xfrd: multi master " "check: zone %s completed transfers", zone->apex_str)); } zone->round_num = -1; /* next try start anew */ zone->multi_master_first_master = -1; xfrd_set_timer_refresh(zone); return; } if(zone->multi_master_first_master < 0) { zone->multi_master_first_master = zone->master_num; zone->multi_master_update_check = -1; } } /* cache ixfr_disabled only for XFRD_NO_IXFR_CACHE time */ if (zone->master->ixfr_disabled && (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= time(NULL)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "clear negative caching ixfr " "disabled for master %s num " "%d ", zone->master->ip_address_spec, zone->master_num)); zone->master->ixfr_disabled = 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s make request round %d mr %d nx %d", zone->apex_str, zone->round_num, zone->master_num, zone->next_master)); /* perform xfr request */ if (!zone->master->use_axfr_only && zone->soa_disk_acquired > 0 && !zone->master->ixfr_disabled) { if (zone->master->allow_udp) { xfrd_set_timer(zone, XFRD_UDP_TIMEOUT); xfrd_udp_obtain(zone); } else { /* doing 3 rounds of IXFR/TCP might not be useful */ xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } } else if (zone->master->use_axfr_only || zone->soa_disk_acquired <= 0) { xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } else if (zone->master->ixfr_disabled) { if (zone->zone_options->pattern->allow_axfr_fallback) { xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_tcp_obtain(xfrd->tcp_set, zone); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s axfr " "fallback not allowed, skipping master %s.", zone->apex_str, zone->master->ip_address_spec)); } } } static void xfrd_udp_obtain(xfrd_zone_type* zone) { assert(zone->udp_waiting == 0); if(zone->tcp_conn != -1) { /* no tcp and udp at the same time */ xfrd_tcp_release(xfrd->tcp_set, zone); } if(xfrd->udp_use_num < XFRD_MAX_UDP) { int fd; xfrd->udp_use_num++; fd = xfrd_send_ixfr_request_udp(zone); if(fd == -1) xfrd->udp_use_num--; else { if(zone->event_added) event_del(&zone->zone_handler); event_set(&zone->zone_handler, fd, EV_PERSIST|EV_READ|EV_TIMEOUT, xfrd_handle_zone, zone); if(event_base_set(xfrd->event_base, &zone->zone_handler) != 0) log_msg(LOG_ERR, "xfrd udp: event_base_set failed"); if(event_add(&zone->zone_handler, &zone->timeout) != 0) log_msg(LOG_ERR, "xfrd udp: event_add failed"); zone->zone_handler_flags=EV_PERSIST|EV_READ|EV_TIMEOUT; zone->event_added = 1; } return; } /* queue the zone as last */ zone->udp_waiting = 1; zone->udp_waiting_next = NULL; zone->udp_waiting_prev = xfrd->udp_waiting_last; if(!xfrd->udp_waiting_first) xfrd->udp_waiting_first = zone; if(xfrd->udp_waiting_last) xfrd->udp_waiting_last->udp_waiting_next = zone; xfrd->udp_waiting_last = zone; xfrd_unset_timer(zone); } time_t xfrd_time() { if(!xfrd->got_time) { xfrd->current_time = time(0); xfrd->got_time = 1; } return xfrd->current_time; } void xfrd_copy_soa(xfrd_soa_type* soa, rr_type* rr) { const uint8_t* rr_ns_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[0]))); uint8_t rr_ns_len = domain_dname(rdata_atom_domain(rr->rdatas[0]))->name_size; const uint8_t* rr_em_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[1]))); uint8_t rr_em_len = domain_dname(rdata_atom_domain(rr->rdatas[1]))->name_size; if(rr->type != TYPE_SOA || rr->rdata_count != 7) { log_msg(LOG_ERR, "xfrd: copy_soa called with bad rr, type %d rrs %u.", rr->type, rr->rdata_count); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: copy_soa rr, type %d rrs %u, ttl %u.", (int)rr->type, (unsigned)rr->rdata_count, (unsigned)rr->ttl)); soa->type = htons(rr->type); soa->klass = htons(rr->klass); soa->ttl = htonl(rr->ttl); soa->rdata_count = htons(rr->rdata_count); /* copy dnames */ soa->prim_ns[0] = rr_ns_len; memcpy(soa->prim_ns+1, rr_ns_wire, rr_ns_len); soa->email[0] = rr_em_len; memcpy(soa->email+1, rr_em_wire, rr_em_len); /* already in network format */ memcpy(&soa->serial, rdata_atom_data(rr->rdatas[2]), sizeof(uint32_t)); memcpy(&soa->refresh, rdata_atom_data(rr->rdatas[3]), sizeof(uint32_t)); memcpy(&soa->retry, rdata_atom_data(rr->rdatas[4]), sizeof(uint32_t)); memcpy(&soa->expire, rdata_atom_data(rr->rdatas[5]), sizeof(uint32_t)); memcpy(&soa->minimum, rdata_atom_data(rr->rdatas[6]), sizeof(uint32_t)); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: copy_soa rr, serial %u refresh %u retry %u expire %u", (unsigned)ntohl(soa->serial), (unsigned)ntohl(soa->refresh), (unsigned)ntohl(soa->retry), (unsigned)ntohl(soa->expire))); } static void xfrd_set_zone_state(xfrd_zone_type* zone, enum xfrd_zone_state s) { if(s != zone->state) { enum xfrd_zone_state old = zone->state; zone->state = s; if((s == xfrd_zone_expired || old == xfrd_zone_expired) && s!=old) { xfrd_send_expire_notification(zone); } } } void xfrd_set_refresh_now(xfrd_zone_type* zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s is activated, state %d", zone->apex_str, zone->state)); if(!zone->is_activated) { /* push onto list */ zone->activated_prev = 0; zone->activated_next = xfrd->activated_first; if(xfrd->activated_first) xfrd->activated_first->activated_prev = zone; xfrd->activated_first = zone; zone->is_activated = 1; } } void xfrd_unset_timer(xfrd_zone_type* zone) { assert(zone->zone_handler.ev_fd == -1); if(zone->event_added) event_del(&zone->zone_handler); zone->zone_handler_flags = 0; zone->event_added = 0; } void xfrd_set_timer(xfrd_zone_type* zone, time_t t) { int fd = zone->zone_handler.ev_fd; int fl = ((fd == -1)?EV_TIMEOUT:zone->zone_handler_flags); /* randomize the time, within 90%-100% of original */ /* not later so zones cannot expire too late */ /* only for times far in the future */ if(t > 10) { time_t base = t*9/10; #ifdef HAVE_ARC4RANDOM_UNIFORM t = base + arc4random_uniform(t-base); #elif HAVE_ARC4RANDOM t = base + arc4random() % (t-base); #else t = base + random()%(t-base); #endif } /* keep existing flags and fd, but re-add with timeout */ if(zone->event_added) event_del(&zone->zone_handler); else fd = -1; zone->timeout.tv_sec = t; zone->timeout.tv_usec = 0; event_set(&zone->zone_handler, fd, fl, xfrd_handle_zone, zone); if(event_base_set(xfrd->event_base, &zone->zone_handler) != 0) log_msg(LOG_ERR, "xfrd timer: event_base_set failed"); if(event_add(&zone->zone_handler, &zone->timeout) != 0) log_msg(LOG_ERR, "xfrd timer: event_add failed"); zone->zone_handler_flags = fl; zone->event_added = 1; } void xfrd_handle_incoming_soa(xfrd_zone_type* zone, xfrd_soa_type* soa, time_t acquired) { if(soa == NULL) { /* nsd no longer has a zone in memory */ zone->soa_nsd_acquired = 0; xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); return; } if(zone->soa_nsd_acquired && soa->serial == zone->soa_nsd.serial) return; if(zone->soa_disk_acquired && soa->serial == zone->soa_disk.serial) { /* soa in disk has been loaded in memory */ log_msg(LOG_INFO, "zone %s serial %u is updated to %u.", zone->apex_str, (unsigned)ntohl(zone->soa_nsd.serial), (unsigned)ntohl(soa->serial)); zone->soa_nsd = zone->soa_disk; zone->soa_nsd_acquired = zone->soa_disk_acquired; xfrd->write_zonefile_needed = 1; /* reset exponential backoff, we got a normal timer now */ zone->fresh_xfr_timeout = 0; if(xfrd_time() - zone->soa_disk_acquired < (time_t)ntohl(zone->soa_disk.refresh)) { /* zone ok, wait for refresh time */ xfrd_set_zone_state(zone, xfrd_zone_ok); zone->round_num = -1; xfrd_set_timer_refresh(zone); } else if(xfrd_time() - zone->soa_disk_acquired < (time_t)ntohl(zone->soa_disk.expire)) { /* zone refreshing */ xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); } if(xfrd_time() - zone->soa_disk_acquired >= (time_t)ntohl(zone->soa_disk.expire)) { /* zone expired */ xfrd_set_zone_state(zone, xfrd_zone_expired); xfrd_set_refresh_now(zone); } if(zone->soa_notified_acquired != 0 && (zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { /* read was in response to this notification */ zone->soa_notified_acquired = 0; } if(zone->soa_notified_acquired && zone->state == xfrd_zone_ok) { /* refresh because of notification */ xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); } xfrd_send_notify(xfrd->notify_zones, zone->apex, &zone->soa_nsd); return; } /* user must have manually provided zone data */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s serial %u from zonefile. refreshing", zone->apex_str, (unsigned)ntohl(soa->serial))); zone->soa_nsd = *soa; zone->soa_disk = *soa; zone->soa_nsd_acquired = acquired; zone->soa_disk_acquired = acquired; if(zone->soa_notified_acquired != 0 && (zone->soa_notified.serial == 0 || compare_serial(ntohl(zone->soa_disk.serial), ntohl(zone->soa_notified.serial)) >= 0)) { /* user provided in response to this notification */ zone->soa_notified_acquired = 0; } xfrd_set_zone_state(zone, xfrd_zone_refreshing); xfrd_set_refresh_now(zone); xfrd_send_notify(xfrd->notify_zones, zone->apex, &zone->soa_nsd); } void xfrd_send_expire_notification(xfrd_zone_type* zone) { task_new_expire(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->apex, zone->state == xfrd_zone_expired); xfrd_set_reload_timeout(); } int 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, src, srclen); if(received == -1) { log_msg(LOG_ERR, "xfrd: recvfrom failed: %s", strerror(errno)); return 0; } buffer_set_limit(packet, received); return 1; } void xfrd_udp_release(xfrd_zone_type* zone) { assert(zone->udp_waiting == 0); if(zone->event_added) event_del(&zone->zone_handler); if(zone->zone_handler.ev_fd != -1) { close(zone->zone_handler.ev_fd); } zone->zone_handler.ev_fd = -1; zone->zone_handler_flags = 0; zone->event_added = 0; /* see if there are waiting zones */ if(xfrd->udp_use_num == XFRD_MAX_UDP) { while(xfrd->udp_waiting_first) { /* snip off waiting list */ xfrd_zone_type* wz = xfrd->udp_waiting_first; assert(wz->udp_waiting); wz->udp_waiting = 0; xfrd->udp_waiting_first = wz->udp_waiting_next; if(wz->udp_waiting_next) wz->udp_waiting_next->udp_waiting_prev = NULL; if(xfrd->udp_waiting_last == wz) xfrd->udp_waiting_last = NULL; /* see if this zone needs udp connection */ if(wz->tcp_conn == -1) { int fd = xfrd_send_ixfr_request_udp(wz); if(fd != -1) { if(wz->event_added) event_del(&wz->zone_handler); event_set(&wz->zone_handler, fd, EV_READ|EV_TIMEOUT|EV_PERSIST, xfrd_handle_zone, wz); if(event_base_set(xfrd->event_base, &wz->zone_handler) != 0) log_msg(LOG_ERR, "cannot set event_base for ixfr"); if(event_add(&wz->zone_handler, &wz->timeout) != 0) log_msg(LOG_ERR, "cannot add event for ixfr"); wz->zone_handler_flags = EV_READ|EV_TIMEOUT|EV_PERSIST; wz->event_added = 1; return; } else { /* make this zone do something with * this failure to act */ xfrd_set_refresh_now(wz); } } } } /* no waiting zones */ if(xfrd->udp_use_num > 0) xfrd->udp_use_num--; } /** disable ixfr for master */ void xfrd_disable_ixfr(xfrd_zone_type* zone) { if(!(zone->master->ixfr_disabled && (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= time(NULL))) { /* start new round, with IXFR disabled */ zone->round_num = 0; zone->next_master = zone->master_num; } zone->master->ixfr_disabled = time(NULL); } 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, NULL, NULL)) { zone->master->bad_xfr_count++; if (zone->master->bad_xfr_count > 2) { xfrd_disable_ixfr(zone); zone->master->bad_xfr_count = 0; } /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); return; } switch(xfrd_handle_received_xfr_packet(zone, xfrd->packet)) { case xfrd_packet_tcp: xfrd_set_timer(zone, xfrd->tcp_set->tcp_timeout); xfrd_udp_release(zone); xfrd_tcp_obtain(xfrd->tcp_set, zone); break; case xfrd_packet_transfer: if(zone->zone_options->pattern->multi_master_check) { xfrd_udp_release(zone); xfrd_make_request(zone); break; } /* fallthrough */ case xfrd_packet_newlease: /* nothing more to do */ assert(zone->round_num == -1); xfrd_udp_release(zone); break; case xfrd_packet_notimpl: xfrd_disable_ixfr(zone); /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_more: case xfrd_packet_drop: /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_bad: default: zone->master->bad_xfr_count++; if (zone->master->bad_xfr_count > 2) { xfrd_disable_ixfr(zone); zone->master->bad_xfr_count = 0; } /* drop packet */ xfrd_udp_release(zone); /* query next server */ xfrd_make_request(zone); break; } } int xfrd_send_udp(struct acl_options* acl, buffer_type* packet, struct acl_options* ifc) { #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif /* INET6 */ int fd, family; /* this will set the remote port to acl->port or TCP_PORT */ socklen_t to_len = xfrd_acl_sockaddr_to(acl, &to); /* get the address family of the remote host */ if(acl->is_ipv6) { #ifdef INET6 family = PF_INET6; #else return -1; #endif /* INET6 */ } else { family = PF_INET; } fd = socket(family, SOCK_DGRAM, IPPROTO_UDP); if(fd == -1) { log_msg(LOG_ERR, "xfrd: cannot create udp socket to %s: %s", acl->ip_address_spec, strerror(errno)); return -1; } /* bind it */ if (!xfrd_bind_local_interface(fd, ifc, acl, 0)) { log_msg(LOG_ERR, "xfrd: cannot bind outgoing interface '%s' to " "udp socket: No matching ip addresses found", ifc->ip_address_spec); close(fd); return -1; } /* send it (udp) */ if(sendto(fd, buffer_current(packet), buffer_remaining(packet), 0, (struct sockaddr*)&to, to_len) == -1) { log_msg(LOG_ERR, "xfrd: sendto %s failed %s", acl->ip_address_spec, strerror(errno)); close(fd); return -1; } return fd; } int xfrd_bind_local_interface(int sockd, struct acl_options* ifc, struct acl_options* acl, int tcp) { #ifdef SO_LINGER struct linger linger = {1, 0}; #endif socklen_t frm_len; #ifdef INET6 struct sockaddr_storage frm; #else struct sockaddr_in frm; #endif /* INET6 */ int ret = 1; if (!ifc) /* no outgoing interface set */ return 1; while (ifc) { if (ifc->is_ipv6 != acl->is_ipv6) { /* check if we have a matching address family */ ifc = ifc->next; continue; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: bind() %s to %s socket", ifc->ip_address_spec, tcp? "tcp":"udp")); ret = 0; frm_len = xfrd_acl_sockaddr_frm(ifc, &frm); if (tcp) { #ifdef SO_REUSEADDR if (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, &frm, frm_len) < 0) { VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt " "SO_REUSEADDR failed: %s", strerror(errno))); } #else VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt SO_REUSEADDR " "failed: SO_REUSEADDR not defined")); #endif /* SO_REUSEADDR */ if (ifc->port != 0) { #ifdef SO_LINGER if (setsockopt(sockd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) < 0) { VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt " "SO_LINGER failed: %s", strerror(errno))); } #else VERBOSITY(2, (LOG_WARNING, "xfrd: setsockopt SO_LINGER " "failed: SO_LINGER not defined")); #endif /* SO_LINGER */ } } /* found one */ if(bind(sockd, (struct sockaddr*)&frm, frm_len) >= 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: bind() %s to %s " "socket was successful", ifc->ip_address_spec, tcp? "tcp":"udp")); return 1; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: bind() %s to %s socket" "failed: %s", ifc->ip_address_spec, tcp? "tcp":"udp", strerror(errno))); log_msg(LOG_WARNING, "xfrd: could not bind source address:port to " "socket: %s", strerror(errno)); /* try another */ ifc = ifc->next; } return ret; } void xfrd_tsig_sign_request(buffer_type* packet, tsig_record_type* tsig, struct acl_options* acl) { tsig_algorithm_type* algo; assert(acl->key_options && acl->key_options->tsig_key); algo = tsig_get_algorithm_by_name(acl->key_options->algorithm); if(!algo) { log_msg(LOG_ERR, "tsig unknown algorithm %s", acl->key_options->algorithm); return; } assert(algo); tsig_init_record(tsig, algo, acl->key_options->tsig_key); tsig_init_query(tsig, ID(packet)); tsig_prepare(tsig); tsig_update(tsig, packet, buffer_position(packet)); tsig_sign(tsig); tsig_append_rr(tsig, packet); ARCOUNT_SET(packet, ARCOUNT(packet) + 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "appending tsig to packet")); /* prepare for validating tsigs */ tsig_prepare(tsig); } static int xfrd_send_ixfr_request_udp(xfrd_zone_type* zone) { int fd; /* make sure we have a master to query the ixfr request to */ assert(zone->master); if(zone->tcp_conn != -1) { /* tcp is using the zone_handler.fd */ log_msg(LOG_ERR, "xfrd: %s tried to send udp whilst tcp engaged", zone->apex_str); return -1; } xfrd_setup_packet(xfrd->packet, TYPE_IXFR, CLASS_IN, zone->apex, qid_generate()); zone->query_id = ID(xfrd->packet); /* delete old xfr file? */ if(zone->msg_seq_nr) xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); zone->msg_seq_nr = 0; zone->msg_rr_count = 0; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "sent query with ID %d", zone->query_id)); NSCOUNT_SET(xfrd->packet, 1); xfrd_write_soa_buffer(xfrd->packet, zone->apex, &zone->soa_disk); /* if we have tsig keys, sign the ixfr query */ if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request(xfrd->packet, &zone->tsig, zone->master); } buffer_flip(xfrd->packet); xfrd_set_timer(zone, XFRD_UDP_TIMEOUT); if((fd = xfrd_send_udp(zone->master, xfrd->packet, zone->zone_options->pattern->outgoing_interface)) == -1) return -1; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd sent udp request for ixfr=%u for zone %s to %s", (unsigned)ntohl(zone->soa_disk.serial), zone->apex_str, zone->master->ip_address_spec)); return fd; } static int xfrd_parse_soa_info(buffer_type* packet, xfrd_soa_type* soa) { if(!buffer_available(packet, 10)) return 0; soa->type = htons(buffer_read_u16(packet)); soa->klass = htons(buffer_read_u16(packet)); soa->ttl = htonl(buffer_read_u32(packet)); if(ntohs(soa->type) != TYPE_SOA || ntohs(soa->klass) != CLASS_IN) { return 0; } if(!buffer_available(packet, buffer_read_u16(packet)) /* rdata length */ || !(soa->prim_ns[0] = dname_make_wire_from_packet(soa->prim_ns+1, packet, 1)) || !(soa->email[0] = dname_make_wire_from_packet(soa->email+1, packet, 1))) { return 0; } soa->rdata_count = 7; /* rdata in SOA */ soa->serial = htonl(buffer_read_u32(packet)); soa->refresh = htonl(buffer_read_u32(packet)); soa->retry = htonl(buffer_read_u32(packet)); soa->expire = htonl(buffer_read_u32(packet)); soa->minimum = htonl(buffer_read_u32(packet)); return 1; } /* * Check the RRs in an IXFR/AXFR reply. * returns 0 on error, 1 on correct parseable packet. * done = 1 if the last SOA in an IXFR/AXFR has been seen. * soa then contains that soa info. * (soa contents is modified by the routine) */ static int xfrd_xfr_check_rrs(xfrd_zone_type* zone, buffer_type* packet, size_t count, int *done, xfrd_soa_type* soa, region_type* temp) { /* first RR has already been checked */ uint32_t tmp_serial = 0; uint16_t type, rrlen; size_t i, soapos, mempos; const dname_type* dname; domain_table_type* owners; rdata_atom_type* rdatas; for(i=0; imsg_rr_count) { if (*done) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr has " "trailing garbage", zone->apex_str)); return 0; } region_free_all(temp); owners = domain_table_create(temp); /* check the dname for errors */ dname = dname_make_from_packet(temp, packet, 1, 1); if(!dname) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr unable " "to parse owner name", zone->apex_str)); return 0; } if(!buffer_available(packet, 10)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr hdr " "too small", zone->apex_str)); return 0; } soapos = buffer_position(packet); type = buffer_read_u16(packet); (void)buffer_read_u16(packet); /* class */ (void)buffer_read_u32(packet); /* ttl */ rrlen = buffer_read_u16(packet); if(!buffer_available(packet, rrlen)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr pkt " "too small", zone->apex_str)); return 0; } mempos = buffer_position(packet); if(rdata_wireformat_to_rdata_atoms(temp, owners, type, rrlen, packet, &rdatas) == -1) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr unable " "to parse rdata", zone->apex_str)); return 0; } if(type == TYPE_SOA) { /* check the SOAs */ buffer_set_position(packet, soapos); if(!xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "unable to parse soainfo", zone->apex_str)); return 0; } if(zone->msg_rr_count == 1 && ntohl(soa->serial) != zone->msg_new_serial) { /* 2nd RR is SOA with lower serial, this is an IXFR */ zone->msg_is_ixfr = 1; if(!zone->soa_disk_acquired) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "got ixfr but need axfr", zone->apex_str)); return 0; /* got IXFR but need AXFR */ } if(ntohl(soa->serial) != ntohl(zone->soa_disk.serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "bad start serial", zone->apex_str)); return 0; /* bad start serial in IXFR */ } zone->msg_old_serial = ntohl(soa->serial); tmp_serial = ntohl(soa->serial); } else if(ntohl(soa->serial) == zone->msg_new_serial) { /* saw another SOA of new serial. */ if(zone->msg_is_ixfr == 1) { zone->msg_is_ixfr = 2; /* seen middle SOA in ixfr */ } else { /* 2nd SOA for AXFR or 3rd newSOA for IXFR */ *done = 1; } } else if (zone->msg_is_ixfr) { /* some additional checks */ if(ntohl(soa->serial) > zone->msg_new_serial) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "bad middle serial", zone->apex_str)); return 0; /* bad middle serial in IXFR */ } if(ntohl(soa->serial) < tmp_serial) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s xfr " "serial decreasing not allowed", zone->apex_str)); return 0; /* middle serial decreases in IXFR */ } /* serial ok, update tmp serial */ tmp_serial = ntohl(soa->serial); } } buffer_set_position(packet, mempos); buffer_skip(packet, rrlen); } /* packet seems to have a valid DNS RR structure */ return 1; } static int xfrd_xfr_process_tsig(xfrd_zone_type* zone, buffer_type* packet) { int have_tsig = 0; assert(zone && zone->master && zone->master->key_options && zone->master->key_options->tsig_key && packet); if(!tsig_find_rr(&zone->tsig, packet)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: malformed tsig RR", zone->apex_str, zone->master->ip_address_spec); return 0; } if(zone->tsig.status == TSIG_OK) { have_tsig = 1; if (zone->tsig.error_code != TSIG_ERROR_NOERROR) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: tsig error " "(%s)", zone->apex_str, zone->master->ip_address_spec, tsig_error(zone->tsig.error_code)); } } if(have_tsig) { /* strip the TSIG resource record off... */ buffer_set_limit(packet, zone->tsig.position); ARCOUNT_SET(packet, ARCOUNT(packet) - 1); } /* keep running the TSIG hash */ tsig_update(&zone->tsig, packet, buffer_limit(packet)); if(have_tsig) { if (!tsig_verify(&zone->tsig)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad tsig signature", zone->apex_str, zone->master->ip_address_spec); return 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, from %s: good tsig signature", zone->apex_str, zone->master->ip_address_spec)); /* prepare for next tsigs */ tsig_prepare(&zone->tsig); } else if(zone->tsig.updates_since_last_prepare > XFRD_TSIG_MAX_UNSIGNED) { /* we allow a number of non-tsig signed packets */ log_msg(LOG_INFO, "xfrd: zone %s, from %s: too many consecutive " "packets without TSIG", zone->apex_str, zone->master->ip_address_spec); return 0; } if(!have_tsig && zone->msg_seq_nr == 0) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: no tsig in first packet of reply", zone->apex_str, zone->master->ip_address_spec); return 0; } return 1; } /* parse the received packet. returns xfrd packet result code. */ static enum xfrd_packet_result xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, xfrd_soa_type* soa) { size_t rr_count; size_t qdcount = QDCOUNT(packet); size_t ancount = ANCOUNT(packet), ancount_todo; size_t nscount = NSCOUNT(packet); int done = 0; region_type* tempregion = NULL; /* has to be axfr / ixfr reply */ if(!buffer_available(packet, QHEADERSZ)) { log_msg(LOG_INFO, "packet too small"); return xfrd_packet_bad; } /* only check ID in first response message. Could also check that * AA bit and QR bit are set, but not needed. */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "got query with ID %d and %d needed", ID(packet), zone->query_id)); if(ID(packet) != zone->query_id) { log_msg(LOG_ERR, "xfrd: zone %s received bad query id from %s, " "dropped", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } /* check RCODE in all response messages */ if(RCODE(packet) != RCODE_OK) { log_msg(LOG_ERR, "xfrd: zone %s received error code %s from " "%s", zone->apex_str, rcode2str(RCODE(packet)), zone->master->ip_address_spec); if (RCODE(packet) == RCODE_IMPL || RCODE(packet) == RCODE_FORMAT) { return xfrd_packet_notimpl; } if (RCODE(packet) != RCODE_NOTAUTH) { /* RFC 2845: If NOTAUTH, client should do TSIG checking */ return xfrd_packet_drop; } } /* check TSIG */ if(zone->master->key_options) { if(!xfrd_xfr_process_tsig(zone, packet)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "dropping xfr reply due " "to bad TSIG")); return xfrd_packet_bad; } } if (RCODE(packet) == RCODE_NOTAUTH) { return xfrd_packet_drop; } buffer_skip(packet, QHEADERSZ); /* skip question section */ for(rr_count = 0; rr_count < qdcount; ++rr_count) { if (!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "xfrd: zone %s, from %s: bad RR in " "question section", zone->apex_str, zone->master->ip_address_spec); return xfrd_packet_bad; } } if(zone->msg_rr_count == 0 && ancount == 0) { if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: TC flagged")); return xfrd_packet_tcp; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: too short xfr packet: no " "answer")); /* if IXFR is unknown, fallback to AXFR (if allowed) */ if (nscount == 1) { if(!packet_skip_dname(packet) || !xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "no SOA begins authority section", zone->apex_str, zone->master->ip_address_spec)); return xfrd_packet_bad; } return xfrd_packet_notimpl; } return xfrd_packet_bad; } ancount_todo = ancount; tempregion = region_create(xalloc, free); if(zone->msg_rr_count == 0) { const dname_type* soaname = dname_make_from_packet(tempregion, packet, 1, 1); if(!soaname) { /* parse failure */ DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "parse error in SOA record", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(dname_compare(soaname, zone->apex) != 0) { /* wrong name */ DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "wrong SOA record", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } /* parse the first RR, see if it is a SOA */ if(!xfrd_parse_soa_info(packet, soa)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "xfrd: zone %s, from %s: " "bad SOA rdata", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->state != xfrd_zone_expired /* if expired - accept anything */ && compare_serial(ntohl(soa->serial), ntohl(zone->soa_disk.serial)) < 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s ignoring old serial from %s", zone->apex_str, zone->master->ip_address_spec)); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s ignoring old serial from %s", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_bad; } if(zone->soa_disk_acquired != 0 && zone->soa_disk.serial == soa->serial) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s got " "update indicating " "current serial", zone->apex_str)); /* (even if notified) the lease on the current soa is renewed */ zone->soa_disk_acquired = xfrd_time(); if(zone->soa_nsd.serial == soa->serial) zone->soa_nsd_acquired = xfrd_time(); xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", zone->apex_str)); if(zone->zone_options->pattern->multi_master_check) { region_destroy(tempregion); return xfrd_packet_drop; } if(zone->soa_notified_acquired == 0) { /* not notified or anything, so stop asking around */ zone->round_num = -1; /* next try start a new round */ xfrd_set_timer_refresh(zone); region_destroy(tempregion); return xfrd_packet_newlease; } /* try next master */ region_destroy(tempregion); return xfrd_packet_drop; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "IXFR reply has ok serial (have \ %u, reply %u).", (unsigned)ntohl(zone->soa_disk.serial), (unsigned)ntohl(soa->serial))); /* serial is newer than soa_disk */ if(ancount == 1) { /* single record means it is like a notify */ (void)xfrd_handle_incoming_notify(zone, soa); } else if(zone->soa_notified_acquired && zone->soa_notified.serial && compare_serial(ntohl(zone->soa_notified.serial), ntohl(soa->serial)) < 0) { /* this AXFR/IXFR notifies me that an even newer serial exists */ zone->soa_notified.serial = soa->serial; } zone->msg_new_serial = ntohl(soa->serial); zone->msg_rr_count = 1; zone->msg_is_ixfr = 0; if(zone->soa_disk_acquired) zone->msg_old_serial = ntohl(zone->soa_disk.serial); else zone->msg_old_serial = 0; ancount_todo = ancount - 1; } if(zone->tcp_conn == -1 && TC(packet)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s received TC from %s. retry tcp.", zone->apex_str, zone->master->ip_address_spec)); region_destroy(tempregion); return xfrd_packet_tcp; } if(zone->tcp_conn == -1 && ancount < 2) { /* too short to be a real ixfr/axfr data transfer: need at */ /* least two RRs in the answer section. */ /* The serial is newer, so try tcp to this master. */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply is short. Try " "tcp anyway.")); region_destroy(tempregion); return xfrd_packet_tcp; } if(!xfrd_xfr_check_rrs(zone, packet, ancount_todo, &done, soa, tempregion)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s sent bad xfr " "reply.", zone->apex_str)); region_destroy(tempregion); return xfrd_packet_bad; } region_destroy(tempregion); if(zone->tcp_conn == -1 && done == 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: udp reply incomplete")); return xfrd_packet_bad; } if(done == 0) return xfrd_packet_more; if(zone->master->key_options) { if(zone->tsig.updates_since_last_prepare != 0) { log_msg(LOG_INFO, "xfrd: last packet of reply has no " "TSIG"); return xfrd_packet_bad; } } return xfrd_packet_transfer; } const char* xfrd_pretty_time(time_t v) { struct tm* tm = localtime(&v); static char buf[64]; if(!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", tm)) snprintf(buf, sizeof(buf), "strftime-err-%u", (unsigned)v); return buf; } enum xfrd_packet_result xfrd_handle_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet) { xfrd_soa_type soa; enum xfrd_packet_result res; uint64_t xfrfile_size; /* parse and check the packet - see if it ends the xfr */ switch((res=xfrd_parse_received_xfr_packet(zone, packet, &soa))) { case xfrd_packet_more: case xfrd_packet_transfer: /* continue with commit */ break; case xfrd_packet_newlease: return xfrd_packet_newlease; case xfrd_packet_tcp: return xfrd_packet_tcp; case xfrd_packet_notimpl: case xfrd_packet_bad: case xfrd_packet_drop: default: { /* rollback */ if(zone->msg_seq_nr > 0) { /* do not process xfr - if only one part simply ignore it. */ /* delete file with previous parts of commit */ xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s " "reverted transfer %u from %s", zone->apex_str, zone->msg_rr_count? (int)zone->msg_new_serial:0, zone->master->ip_address_spec)); zone->msg_seq_nr = 0; } else if (res == xfrd_packet_bad) { VERBOSITY(1, (LOG_INFO, "xfrd: zone %s " "bad transfer %u from %s", zone->apex_str, zone->msg_rr_count? (int)zone->msg_new_serial:0, zone->master->ip_address_spec)); } if (res == xfrd_packet_notimpl) return res; else return xfrd_packet_bad; } } /* dump reply on disk to diff file */ /* if first part, get new filenumber. Numbers can wrap around, 64bit * is enough so we do not collide with older-transfers-in-progress */ if(zone->msg_seq_nr == 0) zone->xfrfilenumber = xfrd->xfrfilenumber++; diff_write_packet(dname_to_string(zone->apex,0), zone->zone_options->pattern->pname, zone->msg_old_serial, zone->msg_new_serial, zone->msg_seq_nr, buffer_begin(packet), buffer_limit(packet), xfrd->nsd, zone->xfrfilenumber); VERBOSITY(3, (LOG_INFO, "xfrd: zone %s written received XFR packet from %s with serial %u to " "disk", zone->apex_str, zone->master->ip_address_spec, (int)zone->msg_new_serial)); zone->msg_seq_nr++; xfrfile_size = xfrd_get_xfrfile_size(xfrd->nsd, zone->xfrfilenumber); if( zone->zone_options->pattern->size_limit_xfr != 0 && xfrfile_size > zone->zone_options->pattern->size_limit_xfr ) { /* xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); xfrd_set_reload_timeout(); */ log_msg(LOG_INFO, "xfrd : transferred zone data was too large %llu", (long long unsigned)xfrfile_size); return xfrd_packet_bad; } if(res == xfrd_packet_more) { /* wait for more */ return xfrd_packet_more; } /* done. we are completely sure of this */ buffer_clear(packet); buffer_printf(packet, "received update to serial %u at %s from %s", (unsigned)zone->msg_new_serial, xfrd_pretty_time(xfrd_time()), zone->master->ip_address_spec); if(zone->master->key_options) { buffer_printf(packet, " TSIG verified with key %s", zone->master->key_options->name); } buffer_flip(packet); diff_write_commit(zone->apex_str, zone->msg_old_serial, zone->msg_new_serial, zone->msg_seq_nr, 1, (char*)buffer_begin(packet), xfrd->nsd, zone->xfrfilenumber); VERBOSITY(1, (LOG_INFO, "xfrd: zone %s committed \"%s\"", zone->apex_str, (char*)buffer_begin(packet))); /* reset msg seq nr, so if that is nonnull we know xfr file exists */ zone->msg_seq_nr = 0; /* now put apply_xfr task on the tasklist */ if(!task_new_apply_xfr(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zone->apex, zone->msg_old_serial, zone->msg_new_serial, zone->xfrfilenumber)) { /* delete the file and pretend transfer was bad to continue */ xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); xfrd_set_reload_timeout(); return xfrd_packet_bad; } /* update the disk serial no. */ zone->soa_disk_acquired = xfrd_time(); zone->soa_disk = soa; if(zone->soa_notified_acquired && ( zone->soa_notified.serial == 0 || compare_serial(htonl(zone->soa_disk.serial), htonl(zone->soa_notified.serial)) >= 0)) { zone->soa_notified_acquired = 0; } if(!zone->soa_notified_acquired) { /* do not set expired zone to ok: * it would cause nsd to start answering * bad data, since the zone is not loaded yet. * if nsd does not reload < retry time, more * queries (for even newer versions) are made. * For expired zone after reload it is set ok (SOAINFO ipc). */ if(zone->state != xfrd_zone_expired) xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is waiting for reload", zone->apex_str)); if(zone->zone_options->pattern->multi_master_check) { zone->multi_master_update_check = zone->master_num; xfrd_set_reload_timeout(); return xfrd_packet_transfer; } zone->round_num = -1; /* next try start anew */ xfrd_set_timer_refresh(zone); xfrd_set_reload_timeout(); return xfrd_packet_transfer; } else { /* try to get an even newer serial */ /* pretend it was bad to continue queries */ xfrd_set_reload_timeout(); return xfrd_packet_bad; } } static void xfrd_set_reload_timeout() { if(xfrd->nsd->options->xfrd_reload_timeout == -1) return; /* automatic reload disabled. */ if(xfrd->reload_timeout.tv_sec == 0 || xfrd_time() >= (time_t)xfrd->reload_timeout.tv_sec ) { /* no reload wait period (or it passed), do it right away */ xfrd_set_reload_now(xfrd); /* start reload wait period */ xfrd->reload_timeout.tv_sec = xfrd_time() + xfrd->nsd->options->xfrd_reload_timeout; xfrd->reload_timeout.tv_usec = 0; return; } /* cannot reload now, set that after the timeout a reload has to happen */ if(xfrd->reload_added == 0) { struct timeval tv; tv.tv_sec = xfrd->reload_timeout.tv_sec - xfrd_time(); tv.tv_usec = 0; if(tv.tv_sec > xfrd->nsd->options->xfrd_reload_timeout) tv.tv_sec = xfrd->nsd->options->xfrd_reload_timeout; event_set(&xfrd->reload_handler, -1, EV_TIMEOUT, xfrd_handle_reload, xfrd); if(event_base_set(xfrd->event_base, &xfrd->reload_handler) != 0) log_msg(LOG_ERR, "cannot set reload event base"); if(event_add(&xfrd->reload_handler, &tv) != 0) log_msg(LOG_ERR, "cannot add reload event"); xfrd->reload_added = 1; } } static void xfrd_handle_reload(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { /* reload timeout */ assert(event & EV_TIMEOUT); (void)event; /* timeout wait period after this request is sent */ xfrd->reload_added = 0; xfrd->reload_timeout.tv_sec = xfrd_time() + xfrd->nsd->options->xfrd_reload_timeout; xfrd_set_reload_now(xfrd); } void xfrd_handle_notify_and_start_xfr(xfrd_zone_type* zone, xfrd_soa_type* soa) { if(xfrd_handle_incoming_notify(zone, soa)) { if(zone->zone_handler.ev_fd == -1 && zone->tcp_conn == -1 && !zone->tcp_waiting && !zone->udp_waiting) { xfrd_set_refresh_now(zone); } /* zones with no content start expbackoff again; this is also * for nsd-control started transfer commands, and also when * the master apparently sends notifies (is back up) */ if(zone->soa_disk_acquired == 0) zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; } } void xfrd_handle_passed_packet(buffer_type* packet, int acl_num, int acl_num_xfr) { uint8_t qnamebuf[MAXDOMAINLEN]; uint16_t qtype, qclass; const dname_type* dname; region_type* tempregion = region_create(xalloc, free); xfrd_zone_type* zone; buffer_skip(packet, QHEADERSZ); if(!packet_read_query_section(packet, qnamebuf, &qtype, &qclass)) { region_destroy(tempregion); return; /* drop bad packet */ } dname = dname_make(tempregion, qnamebuf, 1); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: got passed packet for %s, acl " "%d", dname_to_string(dname,0), acl_num)); /* find the zone */ zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, dname); if(!zone) { /* this could be because the zone has been deleted meanwhile */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "xfrd: incoming packet for " "unknown zone %s", dname_to_string(dname,0))); region_destroy(tempregion); return; /* drop packet for unknown zone */ } region_destroy(tempregion); /* handle */ if(OPCODE(packet) == OPCODE_NOTIFY) { xfrd_soa_type soa; int have_soa = 0; int next; /* get serial from a SOA */ if(ANCOUNT(packet) == 1 && packet_skip_dname(packet) && xfrd_parse_soa_info(packet, &soa)) { have_soa = 1; } xfrd_handle_notify_and_start_xfr(zone, have_soa?&soa:NULL); /* First, see if our notifier has a match in provide-xfr */ if (acl_find_num(zone->zone_options->pattern->request_xfr, acl_num_xfr)) next = acl_num_xfr; else /* If not, find master that matches notifiers ACL entry */ next = find_same_master_notify(zone, acl_num); if(next != -1) { zone->next_master = next; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: notify set next master to query %d", next)); } } else { /* ignore other types of messages */ } } static int xfrd_handle_incoming_notify(xfrd_zone_type* zone, xfrd_soa_type* soa) { if(soa && zone->soa_disk_acquired && zone->state != xfrd_zone_expired && compare_serial(ntohl(soa->serial),ntohl(zone->soa_disk.serial)) <= 0) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: ignored notify %s %u old serial, zone valid " "(soa disk serial %u)", zone->apex_str, (unsigned)ntohl(soa->serial), (unsigned)ntohl(zone->soa_disk.serial))); return 0; /* ignore notify with old serial, we have a valid zone */ } if(soa == 0) { zone->soa_notified.serial = 0; } else if (zone->soa_notified_acquired == 0 || zone->soa_notified.serial == 0 || compare_serial(ntohl(soa->serial), ntohl(zone->soa_notified.serial)) > 0) { zone->soa_notified = *soa; } zone->soa_notified_acquired = xfrd_time(); if(zone->state == xfrd_zone_ok) { xfrd_set_zone_state(zone, xfrd_zone_refreshing); } /* transfer right away */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Handle incoming notify for zone %s", zone->apex_str)); return 1; } static int find_same_master_notify(xfrd_zone_type* zone, int acl_num_nfy) { struct acl_options* nfy_acl = acl_find_num(zone->zone_options->pattern-> allow_notify, acl_num_nfy); int num = 0; struct acl_options* master = zone->zone_options->pattern->request_xfr; if(!nfy_acl) return -1; while(master) { if(acl_addr_matches_host(nfy_acl, master)) return num; master = master->next; num++; } return -1; } void xfrd_check_failed_updates() { /* see if updates have not come through */ xfrd_zone_type* zone; RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { /* zone has a disk soa, and no nsd soa or a different nsd soa */ if(zone->soa_disk_acquired != 0 && (zone->soa_nsd_acquired == 0 || zone->soa_disk.serial != zone->soa_nsd.serial)) { if(zone->soa_disk_acquired < xfrd->reload_cmd_last_sent) { /* this zone should have been loaded, since its disk soa time is before the time of the reload cmd. */ xfrd_soa_type dumped_soa = zone->soa_disk; log_msg(LOG_ERR, "xfrd: zone %s: soa serial %u " "update failed, restarting " "transfer (notified zone)", zone->apex_str, (unsigned)ntohl(zone->soa_disk.serial)); /* revert the soa; it has not been acquired properly */ if(zone->soa_disk_acquired == zone->soa_nsd_acquired) { /* this was the same as served, * perform force_axfr , re-download * same serial from master */ zone->soa_disk_acquired = 0; zone->soa_nsd_acquired = 0; } else { /* revert soa to the one in server */ zone->soa_disk_acquired = zone->soa_nsd_acquired; zone->soa_disk = zone->soa_nsd; } /* pretend we are notified with disk soa. This will cause a refetch of the data, and reload. */ xfrd_handle_incoming_notify(zone, &dumped_soa); xfrd_set_timer_refresh(zone); } else if(zone->soa_disk_acquired >= xfrd->reload_cmd_last_sent) { /* this zone still has to be loaded, make sure reload is set to be sent. */ if(xfrd->need_to_send_reload == 0 && xfrd->reload_added == 0) { log_msg(LOG_ERR, "xfrd: zone %s: needs " "to be loaded. reload lost? " "try again", zone->apex_str); xfrd_set_reload_timeout(); } } } } } void xfrd_prepare_zones_for_reload() { xfrd_zone_type* zone; RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { /* zone has a disk soa, and no nsd soa or a different nsd soa */ if(zone->soa_disk_acquired != 0 && (zone->soa_nsd_acquired == 0 || zone->soa_disk.serial != zone->soa_nsd.serial)) { if(zone->soa_disk_acquired == xfrd_time()) { /* antedate by one second. * this makes sure that the zone time is before * reload, so that check_failed_zones() is * certain of the result. */ zone->soa_disk_acquired--; } } } } struct buffer* xfrd_get_temp_buffer() { return xfrd->packet; } #ifdef BIND8_STATS /** process stat info task */ static void xfrd_process_stat_info_task(xfrd_state_type* xfrd, struct task_list_d* task) { size_t i; stc_type* p = (void*)task->zname + sizeof(struct nsdst); stats_add(&xfrd->nsd->st, (struct nsdst*)task->zname); for(i=0; insd->child_count; i++) { xfrd->nsd->children[i].query_count += *p++; } /* got total, now see if users are interested in these statistics */ #ifdef HAVE_SSL daemon_remote_process_stats(xfrd->nsd->rc); #endif } #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS /** process zonestat inc task */ static void xfrd_process_zonestat_inc_task(xfrd_state_type* xfrd, struct task_list_d* task) { xfrd->zonestat_safe = (unsigned)task->oldserial; zonestat_remap(xfrd->nsd, 0, xfrd->zonestat_safe*sizeof(struct nsdst)); xfrd->nsd->zonestatsize[0] = xfrd->zonestat_safe; zonestat_remap(xfrd->nsd, 1, xfrd->zonestat_safe*sizeof(struct nsdst)); xfrd->nsd->zonestatsize[1] = xfrd->zonestat_safe; } #endif /* USE_ZONE_STATS */ static void xfrd_handle_taskresult(xfrd_state_type* xfrd, struct task_list_d* task) { #ifndef BIND8_STATS (void)xfrd; #endif switch(task->task_type) { case task_soa_info: xfrd_process_soa_info_task(task); break; #ifdef BIND8_STATS case task_stat_info: xfrd_process_stat_info_task(xfrd, task); break; #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS case task_zonestat_inc: xfrd_process_zonestat_inc_task(xfrd, task); break; #endif default: log_msg(LOG_WARNING, "unhandled task result in xfrd from " "reload type %d", (int)task->task_type); } } void xfrd_process_task_result(xfrd_state_type* xfrd, struct udb_base* taskudb) { udb_ptr t; /* remap it for usage */ task_remap(taskudb); /* process the task-results in the taskudb */ udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); while(!udb_ptr_is_null(&t)) { xfrd_handle_taskresult(xfrd, TASKLIST(&t)); udb_ptr_set_rptr(&t, taskudb, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, taskudb); /* clear the udb so it can be used by xfrd to make new tasks for * reload, this happens when the reload signal is sent, and thus * the taskudbs are swapped */ task_clear(taskudb); #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif } void xfrd_set_reload_now(xfrd_state_type* xfrd) { #ifdef HAVE_SYSTEMD sd_notify(0, "RELOADING=1"); #endif xfrd->need_to_send_reload = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } static void xfrd_handle_write_timer(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { /* timeout for write events */ assert(event & EV_TIMEOUT); (void)event; if(xfrd->nsd->options->zonefiles_write == 0) return; /* call reload to write changed zonefiles */ if(!xfrd->write_zonefile_needed) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "zonefiles write timer (nothing)")); xfrd_write_timer_set(); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "zonefiles write timer")); task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, NULL); xfrd_set_reload_now(xfrd); xfrd->write_zonefile_needed = 0; xfrd_write_timer_set(); } static void xfrd_write_timer_set() { struct timeval tv; if(xfrd->nsd->options->zonefiles_write == 0) return; tv.tv_sec = xfrd->nsd->options->zonefiles_write; tv.tv_usec = 0; event_set(&xfrd->write_timer, -1, EV_TIMEOUT, xfrd_handle_write_timer, xfrd); if(event_base_set(xfrd->event_base, &xfrd->write_timer) != 0) log_msg(LOG_ERR, "xfrd write timer: event_base_set failed"); if(event_add(&xfrd->write_timer, &tv) != 0) log_msg(LOG_ERR, "xfrd write timer: event_add failed"); } static void xfrd_handle_child_timer(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) { assert(event & EV_TIMEOUT); (void)event; /* only used to wakeup the process to reap children, note the * event is no longer registered */ xfrd->child_timer_added = 0; } nsd-4.1.26/zonec.c0000664000175000017500000011445013243027363013320 0ustar wouterwouter/* * zonec.c -- zone compiler. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include #include #include #ifdef HAVE_SYS_STAT_H #include #endif #include #ifdef HAVE_NETDB_H #include #endif #include "zonec.h" #include "dname.h" #include "dns.h" #include "namedb.h" #include "rdata.h" #include "region-allocator.h" #include "util.h" #include "zparser.h" #include "options.h" #include "nsec3.h" #define ILNP_MAXDIGITS 4 #define ILNP_NUMGROUPS 4 const dname_type *error_dname; domain_type *error_domain; static time_t startzonec = 0; static long int totalrrs = 0; extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]; extern uint16_t nsec_highest_rcode; /* * Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first * element. Return a pointer to the allocation. */ static uint16_t * alloc_rdata(region_type *region, size_t size) { uint16_t *result = region_alloc(region, sizeof(uint16_t) + size); *result = size; return result; } uint16_t * alloc_rdata_init(region_type *region, const void *data, size_t size) { uint16_t *result = region_alloc(region, sizeof(uint16_t) + size); *result = size; memcpy(result + 1, data, size); return result; } /* * These are parser function for generic zone file stuff. */ uint16_t * zparser_conv_hex(region_type *region, const char *hex, size_t len) { /* convert a hex value to wireformat */ uint16_t *r = NULL; uint8_t *t; int i; if(len == 1 && hex[0] == '0') { /* single 0 represents empty buffer */ return alloc_rdata(region, 0); } if (len % 2 != 0) { zc_error_prev_line("number of hex digits must be a multiple of 2"); } else if (len > MAX_RDLENGTH * 2) { zc_error_prev_line("hex data exceeds maximum rdata length (%d)", MAX_RDLENGTH); } else { /* the length part */ r = alloc_rdata(region, len/2); t = (uint8_t *)(r + 1); /* Now process octet by octet... */ while (*hex) { *t = 0; for (i = 16; i >= 1; i -= 15) { if (isxdigit((unsigned char)*hex)) { *t += hexdigit_to_int(*hex) * i; } else { zc_error_prev_line( "illegal hex character '%c'", (int) *hex); return NULL; } ++hex; } ++t; } } return r; } /* convert hex, precede by a 1-byte length */ uint16_t * zparser_conv_hex_length(region_type *region, const char *hex, size_t len) { uint16_t *r = NULL; uint8_t *t; int i; if (len % 2 != 0) { zc_error_prev_line("number of hex digits must be a multiple of 2"); } else if (len > 255 * 2) { zc_error_prev_line("hex data exceeds 255 bytes"); } else { uint8_t *l; /* the length part */ r = alloc_rdata(region, len/2+1); t = (uint8_t *)(r + 1); l = t++; *l = '\0'; /* Now process octet by octet... */ while (*hex) { *t = 0; for (i = 16; i >= 1; i -= 15) { if (isxdigit((unsigned char)*hex)) { *t += hexdigit_to_int(*hex) * i; } else { zc_error_prev_line( "illegal hex character '%c'", (int) *hex); return NULL; } ++hex; } ++t; ++*l; } } return r; } uint16_t * zparser_conv_time(region_type *region, const char *time) { /* convert a time YYHM to wireformat */ uint16_t *r = NULL; struct tm tm; /* Try to scan the time... */ if (!strptime(time, "%Y%m%d%H%M%S", &tm)) { zc_error_prev_line("date and time is expected"); } else { uint32_t l = htonl(mktime_from_utc(&tm)); r = alloc_rdata_init(region, &l, sizeof(l)); } return r; } uint16_t * zparser_conv_services(region_type *region, const char *protostr, char *servicestr) { /* * Convert a protocol and a list of service port numbers * (separated by spaces) in the rdata to wireformat */ uint16_t *r = NULL; uint8_t *p; uint8_t bitmap[65536/8]; char sep[] = " "; char *word; int max_port = -8; /* convert a protocol in the rdata to wireformat */ struct protoent *proto; memset(bitmap, 0, sizeof(bitmap)); proto = getprotobyname(protostr); if (!proto) { proto = getprotobynumber(atoi(protostr)); } if (!proto) { zc_error_prev_line("unknown protocol '%s'", protostr); return NULL; } for (word = strtok(servicestr, sep); word; word = strtok(NULL, sep)) { struct servent *service; int port; service = getservbyname(word, proto->p_name); if (service) { /* Note: ntohs not ntohl! Strange but true. */ port = ntohs((uint16_t) service->s_port); } else { char *end; port = strtol(word, &end, 10); if (*end != '\0') { zc_error_prev_line("unknown service '%s' for protocol '%s'", word, protostr); continue; } } if (port < 0 || port > 65535) { zc_error_prev_line("bad port number %d", port); } else { set_bit(bitmap, port); if (port > max_port) max_port = port; } } r = alloc_rdata(region, sizeof(uint8_t) + max_port / 8 + 1); p = (uint8_t *) (r + 1); *p = proto->p_proto; memcpy(p + 1, bitmap, *r-1); return r; } uint16_t * zparser_conv_serial(region_type *region, const char *serialstr) { uint16_t *r = NULL; uint32_t serial; const char *t; serial = strtoserial(serialstr, &t); if (*t != '\0') { zc_error_prev_line("serial is expected or serial too big"); } else { serial = htonl(serial); r = alloc_rdata_init(region, &serial, sizeof(serial)); } return r; } uint16_t * zparser_conv_period(region_type *region, const char *periodstr) { /* convert a time period (think TTL's) to wireformat) */ uint16_t *r = NULL; uint32_t period; const char *end; /* Allocate required space... */ period = strtottl(periodstr, &end); if (*end != '\0') { zc_error_prev_line("time period is expected"); } else { period = htonl(period); r = alloc_rdata_init(region, &period, sizeof(period)); } return r; } uint16_t * zparser_conv_short(region_type *region, const char *text) { uint16_t *r = NULL; uint16_t value; char *end; value = htons((uint16_t) strtol(text, &end, 10)); if (*end != '\0') { zc_error_prev_line("integer value is expected"); } else { r = alloc_rdata_init(region, &value, sizeof(value)); } return r; } uint16_t * zparser_conv_byte(region_type *region, const char *text) { uint16_t *r = NULL; uint8_t value; char *end; value = (uint8_t) strtol(text, &end, 10); if (*end != '\0') { zc_error_prev_line("integer value is expected"); } else { r = alloc_rdata_init(region, &value, sizeof(value)); } return r; } uint16_t * zparser_conv_algorithm(region_type *region, const char *text) { const lookup_table_type *alg; uint8_t id; alg = lookup_by_name(dns_algorithms, text); if (alg) { id = (uint8_t) alg->id; } else { char *end; id = (uint8_t) strtol(text, &end, 10); if (*end != '\0') { zc_error_prev_line("algorithm is expected"); return NULL; } } return alloc_rdata_init(region, &id, sizeof(id)); } uint16_t * zparser_conv_certificate_type(region_type *region, const char *text) { /* convert an algorithm string to integer */ const lookup_table_type *type; uint16_t id; type = lookup_by_name(dns_certificate_types, text); if (type) { id = htons((uint16_t) type->id); } else { char *end; id = htons((uint16_t) strtol(text, &end, 10)); if (*end != '\0') { zc_error_prev_line("certificate type is expected"); return NULL; } } return alloc_rdata_init(region, &id, sizeof(id)); } uint16_t * zparser_conv_a(region_type *region, const char *text) { in_addr_t address; uint16_t *r = NULL; if (inet_pton(AF_INET, text, &address) != 1) { zc_error_prev_line("invalid IPv4 address '%s'", text); } else { r = alloc_rdata_init(region, &address, sizeof(address)); } return r; } uint16_t * zparser_conv_aaaa(region_type *region, const char *text) { uint8_t address[IP6ADDRLEN]; uint16_t *r = NULL; if (inet_pton(AF_INET6, text, address) != 1) { zc_error_prev_line("invalid IPv6 address '%s'", text); } else { r = alloc_rdata_init(region, address, sizeof(address)); } return r; } uint16_t * zparser_conv_ilnp64(region_type *region, const char *text) { uint16_t *r = NULL; int ngroups, num; unsigned long hex; const char *ch; char digits[ILNP_MAXDIGITS+1]; unsigned int ui[ILNP_NUMGROUPS]; uint16_t a[ILNP_NUMGROUPS]; ngroups = 1; /* Always at least one group */ num = 0; for (ch = text; *ch != '\0'; ch++) { if (*ch == ':') { if (num <= 0) { zc_error_prev_line("ilnp64: empty group of " "digits is not allowed"); return NULL; } digits[num] = '\0'; hex = (unsigned long) strtol(digits, NULL, 16); num = 0; ui[ngroups - 1] = hex; if (ngroups >= ILNP_NUMGROUPS) { zc_error_prev_line("ilnp64: more than %d groups " "of digits", ILNP_NUMGROUPS); return NULL; } ngroups++; } else { /* Our grammar is stricter than the one accepted by * strtol. */ if (!isxdigit((unsigned char)*ch)) { zc_error_prev_line("ilnp64: invalid " "(non-hexadecimal) character %c", *ch); return NULL; } if (num >= ILNP_MAXDIGITS) { zc_error_prev_line("ilnp64: more than %d digits " "in a group", ILNP_MAXDIGITS); return NULL; } digits[num++] = *ch; } } if (num <= 0) { zc_error_prev_line("ilnp64: empty group of digits is not " "allowed"); return NULL; } digits[num] = '\0'; hex = (unsigned long) strtol(digits, NULL, 16); ui[ngroups - 1] = hex; if (ngroups < 4) { zc_error_prev_line("ilnp64: less than %d groups of digits", ILNP_NUMGROUPS); return NULL; } a[0] = htons(ui[0]); a[1] = htons(ui[1]); a[2] = htons(ui[2]); a[3] = htons(ui[3]); r = alloc_rdata_init(region, a, sizeof(a)); return r; } static uint16_t * zparser_conv_eui48(region_type *region, const char *text) { uint8_t nums[6]; uint16_t *r = NULL; unsigned int a, b, c, d, e, f; int l; if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x%n", &a, &b, &c, &d, &e, &f, &l) != 6 || l != (int)strlen(text)){ zc_error_prev_line("eui48: invalid rr"); return NULL; } nums[0] = (uint8_t)a; nums[1] = (uint8_t)b; nums[2] = (uint8_t)c; nums[3] = (uint8_t)d; nums[4] = (uint8_t)e; nums[5] = (uint8_t)f; r = alloc_rdata_init(region, nums, sizeof(nums)); return r; } static uint16_t * zparser_conv_eui64(region_type *region, const char *text) { uint8_t nums[8]; uint16_t *r = NULL; unsigned int a, b, c, d, e, f, g, h; int l; if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || l != (int)strlen(text)) { zc_error_prev_line("eui64: invalid rr"); return NULL; } nums[0] = (uint8_t)a; nums[1] = (uint8_t)b; nums[2] = (uint8_t)c; nums[3] = (uint8_t)d; nums[4] = (uint8_t)e; nums[5] = (uint8_t)f; nums[6] = (uint8_t)g; nums[7] = (uint8_t)h; r = alloc_rdata_init(region, nums, sizeof(nums)); return r; } uint16_t * zparser_conv_eui(region_type *region, const char *text, size_t len) { uint16_t *r = NULL; int nnum, num; const char* ch; nnum = len/8; num = 1; for (ch = text; *ch != '\0'; ch++) { if (*ch == '-') { num++; } else if (!isxdigit((unsigned char)*ch)) { zc_error_prev_line("eui%u: invalid (non-hexadecimal) " "character %c", (unsigned) len, *ch); return NULL; } } if (num != nnum) { zc_error_prev_line("eui%u: wrong number of hex numbers", (unsigned) len); return NULL; } switch (len) { case 48: r = zparser_conv_eui48(region, text); break; case 64: r = zparser_conv_eui64(region, text); break; default: zc_error_prev_line("eui%u: invalid length", (unsigned) len); return NULL; break; } return r; } uint16_t * zparser_conv_text(region_type *region, const char *text, size_t len) { uint16_t *r = NULL; uint8_t *p; if (len > 255) { zc_error_prev_line("text string is longer than 255 characters," " try splitting it into multiple parts"); len = 255; } r = alloc_rdata(region, len + 1); p = (uint8_t *) (r + 1); *p = len; memcpy(p + 1, text, len); return r; } /* for CAA Value [RFC 6844] */ uint16_t * zparser_conv_long_text(region_type *region, const char *text, size_t len) { uint16_t *r = NULL; if (len > MAX_RDLENGTH) { zc_error_prev_line("text string is longer than max rdlen"); return NULL; } r = alloc_rdata_init(region, text, len); return r; } /* for CAA Tag [RFC 6844] */ uint16_t * zparser_conv_tag(region_type *region, const char *text, size_t len) { uint16_t *r = NULL; uint8_t *p; const char* ptr; if (len < 1) { zc_error_prev_line("invalid tag: zero length"); return NULL; } if (len > 15) { zc_error_prev_line("invalid tag %s: longer than 15 characters (%u)", text, (unsigned) len); return NULL; } for (ptr = text; *ptr; ptr++) { if (!isdigit((unsigned char)*ptr) && !islower((unsigned char)*ptr)) { zc_error_prev_line("invalid tag %s: contains invalid char %c", text, *ptr); return NULL; } } r = alloc_rdata(region, len + 1); p = (uint8_t *) (r + 1); *p = len; memmove(p + 1, text, len); return r; } uint16_t * zparser_conv_dns_name(region_type *region, const uint8_t* name, size_t len) { uint16_t* r = NULL; uint8_t* p = NULL; r = alloc_rdata(region, len); p = (uint8_t *) (r + 1); memcpy(p, name, len); return r; } uint16_t * zparser_conv_b32(region_type *region, const char *b32) { uint8_t buffer[B64BUFSIZE]; uint16_t *r = NULL; int i; if(strcmp(b32, "-") == 0) { return alloc_rdata_init(region, "", 1); } i = b32_pton(b32, buffer+1, B64BUFSIZE-1); if (i == -1 || i > 255) { zc_error_prev_line("invalid base32 data"); } else { buffer[0] = i; /* store length byte */ r = alloc_rdata_init(region, buffer, i+1); } return r; } uint16_t * zparser_conv_b64(region_type *region, const char *b64) { uint8_t buffer[B64BUFSIZE]; uint16_t *r = NULL; int i; if(strcmp(b64, "0") == 0) { /* single 0 represents empty buffer */ return alloc_rdata(region, 0); } i = b64_pton(b64, buffer, B64BUFSIZE); if (i == -1) { zc_error_prev_line("invalid base64 data"); } else { r = alloc_rdata_init(region, buffer, i); } return r; } uint16_t * zparser_conv_rrtype(region_type *region, const char *text) { uint16_t *r = NULL; uint16_t type = rrtype_from_string(text); if (type == 0) { zc_error_prev_line("unrecognized RR type '%s'", text); } else { type = htons(type); r = alloc_rdata_init(region, &type, sizeof(type)); } return r; } uint16_t * zparser_conv_nxt(region_type *region, uint8_t nxtbits[]) { /* nxtbits[] consists of 16 bytes with some zero's in it * copy every byte with zero to r and write the length in * the first byte */ uint16_t i; uint16_t last = 0; for (i = 0; i < 16; i++) { if (nxtbits[i] != 0) last = i + 1; } return alloc_rdata_init(region, nxtbits, last); } /* we potentially have 256 windows, each one is numbered. empty ones * should be discarded */ uint16_t * zparser_conv_nsec(region_type *region, uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]) { /* nsecbits contains up to 64K of bits which represent the * types available for a name. Walk the bits according to * nsec++ draft from jakob */ uint16_t *r; uint8_t *ptr; size_t i,j; uint16_t window_count = 0; uint16_t total_size = 0; uint16_t window_max = 0; /* The used windows. */ int used[NSEC_WINDOW_COUNT]; /* The last byte used in each the window. */ int size[NSEC_WINDOW_COUNT]; window_max = 1 + (nsec_highest_rcode / 256); /* used[i] is the i-th window included in the nsec * size[used[0]] is the size of window 0 */ /* walk through the 256 windows */ for (i = 0; i < window_max; ++i) { int empty_window = 1; /* check each of the 32 bytes */ for (j = 0; j < NSEC_WINDOW_BITS_SIZE; ++j) { if (nsecbits[i][j] != 0) { size[i] = j + 1; empty_window = 0; } } if (!empty_window) { used[window_count] = i; window_count++; } } for (i = 0; i < window_count; ++i) { total_size += sizeof(uint16_t) + size[used[i]]; } r = alloc_rdata(region, total_size); ptr = (uint8_t *) (r + 1); /* now walk used and copy it */ for (i = 0; i < window_count; ++i) { ptr[0] = used[i]; ptr[1] = size[used[i]]; memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]); ptr += size[used[i]] + 2; } return r; } /* Parse an int terminated in the specified range. */ static int parse_int(const char *str, char **end, int *result, const char *name, int min, int max) { *result = (int) strtol(str, end, 10); if (*result < min || *result > max) { zc_error_prev_line("%s must be within the range [%d .. %d]", name, min, max); return 0; } else { return 1; } } /* RFC1876 conversion routines */ static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, 1000000,10000000,100000000,1000000000}; /* * Converts ascii size/precision X * 10**Y(cm) to 0xXY. * Sets the given pointer to the last used character. * */ static uint8_t precsize_aton (char *cp, char **endptr) { unsigned int mval = 0, cmval = 0; uint8_t retval = 0; int exponent; int mantissa; while (isdigit((unsigned char)*cp)) mval = mval * 10 + hexdigit_to_int(*cp++); if (*cp == '.') { /* centimeters */ cp++; if (isdigit((unsigned char)*cp)) { cmval = hexdigit_to_int(*cp++) * 10; if (isdigit((unsigned char)*cp)) { cmval += hexdigit_to_int(*cp++); } } } if(mval >= poweroften[7]) { assert(poweroften[7] != 0); /* integer overflow possible for *100 */ mantissa = mval / poweroften[7]; exponent = 9; /* max */ } else { cmval = (mval * 100) + cmval; for (exponent = 0; exponent < 9; exponent++) if (cmval < poweroften[exponent+1]) break; assert(poweroften[exponent] != 0); mantissa = cmval / poweroften[exponent]; } if (mantissa > 9) mantissa = 9; retval = (mantissa << 4) | exponent; if (*cp == 'm') cp++; *endptr = cp; return (retval); } /* * Parses a specific part of rdata. * * Returns: * * number of elements parsed * zero on error * */ uint16_t * zparser_conv_loc(region_type *region, char *str) { uint16_t *r; uint32_t *p; int i; int deg, min, secs; /* Secs is stored times 1000. */ uint32_t lat = 0, lon = 0, alt = 0; /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */ uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13}; char *start; double d; for(;;) { deg = min = secs = 0; /* Degrees */ if (*str == '\0') { zc_error_prev_line("unexpected end of LOC data"); return NULL; } if (!parse_int(str, &str, °, "degrees", 0, 180)) return NULL; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after degrees"); return NULL; } ++str; /* Minutes? */ if (isdigit((unsigned char)*str)) { if (!parse_int(str, &str, &min, "minutes", 0, 60)) return NULL; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after minutes"); return NULL; } ++str; } /* Seconds? */ if (isdigit((unsigned char)*str)) { start = str; if (!parse_int(str, &str, &i, "seconds", 0, 60)) { return NULL; } if (*str == '.' && !parse_int(str + 1, &str, &i, "seconds fraction", 0, 999)) { return NULL; } if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after seconds"); return NULL; } /* No need for precision specifiers, it's a double */ if (sscanf(start, "%lf", &d) != 1) { zc_error_prev_line("error parsing seconds"); } if (d < 0.0 || d > 60.0) { zc_error_prev_line("seconds not in range 0.0 .. 60.0"); } secs = (int) (d * 1000.0 + 0.5); ++str; } switch(*str) { case 'N': case 'n': lat = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); break; case 'E': case 'e': lon = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); break; case 'S': case 's': lat = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); break; case 'W': case 'w': lon = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); break; default: zc_error_prev_line("invalid latitude/longtitude: '%c'", *str); return NULL; } ++str; if (lat != 0 && lon != 0) break; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after latitude/longitude"); return NULL; } ++str; } /* Altitude */ if (*str == '\0') { zc_error_prev_line("unexpected end of LOC data"); return NULL; } if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected before altitude"); return NULL; } ++str; start = str; /* Sign */ if (*str == '+' || *str == '-') { ++str; } /* Meters of altitude... */ if(strtol(str, &str, 10) == LONG_MAX) { zc_error_prev_line("altitude too large, number overflow"); return NULL; } switch(*str) { case ' ': case '\0': case 'm': break; case '.': if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) { return NULL; } if (!isspace((unsigned char)*str) && *str != '\0' && *str != 'm') { zc_error_prev_line("altitude fraction must be a number"); return NULL; } break; default: zc_error_prev_line("altitude must be expressed in meters"); return NULL; } if (!isspace((unsigned char)*str) && *str != '\0') ++str; if (sscanf(start, "%lf", &d) != 1) { zc_error_prev_line("error parsing altitude"); } alt = (uint32_t) (10000000.0 + d * 100 + 0.5); if (!isspace((unsigned char)*str) && *str != '\0') { zc_error_prev_line("unexpected character after altitude"); return NULL; } /* Now parse size, horizontal precision and vertical precision if any */ for(i = 1; isspace((unsigned char)*str) && i <= 3; i++) { vszhpvp[i] = precsize_aton(str + 1, &str); if (!isspace((unsigned char)*str) && *str != '\0') { zc_error_prev_line("invalid size or precision"); return NULL; } } /* Allocate required space... */ r = alloc_rdata(region, 16); p = (uint32_t *) (r + 1); memmove(p, vszhpvp, 4); write_uint32(p + 1, lat); write_uint32(p + 2, lon); write_uint32(p + 3, alt); return r; } /* * Convert an APL RR RDATA element. */ uint16_t * zparser_conv_apl_rdata(region_type *region, char *str) { int negated = 0; uint16_t address_family; uint8_t prefix; uint8_t maximum_prefix; uint8_t length; uint8_t address[IP6ADDRLEN]; char *colon = strchr(str, ':'); char *slash = strchr(str, '/'); int af; int rc; uint16_t rdlength; uint16_t *r; uint8_t *t; char *end; long p; if (!colon) { zc_error("address family separator is missing"); return NULL; } if (!slash) { zc_error("prefix separator is missing"); return NULL; } *colon = '\0'; *slash = '\0'; if (*str == '!') { negated = 1; ++str; } if (strcmp(str, "1") == 0) { address_family = htons(1); af = AF_INET; length = sizeof(in_addr_t); maximum_prefix = length * 8; } else if (strcmp(str, "2") == 0) { address_family = htons(2); af = AF_INET6; length = IP6ADDRLEN; maximum_prefix = length * 8; } else { zc_error("invalid address family '%s'", str); return NULL; } rc = inet_pton(af, colon + 1, address); if (rc == 0) { zc_error("invalid address '%s'", colon + 1); return NULL; } else if (rc == -1) { zc_error("inet_pton failed: %s", strerror(errno)); return NULL; } /* Strip trailing zero octets. */ while (length > 0 && address[length - 1] == 0) --length; p = strtol(slash + 1, &end, 10); if (p < 0 || p > maximum_prefix) { zc_error("prefix not in the range 0 .. %d", maximum_prefix); return NULL; } else if (*end != '\0') { zc_error("invalid prefix '%s'", slash + 1); return NULL; } prefix = (uint8_t) p; rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length) + length); r = alloc_rdata(region, rdlength); t = (uint8_t *) (r + 1); memcpy(t, &address_family, sizeof(address_family)); t += sizeof(address_family); memcpy(t, &prefix, sizeof(prefix)); t += sizeof(prefix); memcpy(t, &length, sizeof(length)); if (negated) { *t |= APL_NEGATION_MASK; } t += sizeof(length); memcpy(t, address, length); return r; } /* * Below some function that also convert but not to wireformat * but to "normal" (int,long,char) types */ uint32_t zparser_ttl2int(const char *ttlstr, int* error) { /* convert a ttl value to a integer * return the ttl in a int * -1 on error */ uint32_t ttl; const char *t; ttl = strtottl(ttlstr, &t); if (*t != 0) { zc_error_prev_line("invalid TTL value: %s",ttlstr); *error = 1; } return ttl; } void zadd_rdata_wireformat(uint16_t *data) { if (parser->current_rr.rdata_count >= MAXRDATALEN) { zc_error_prev_line("too many rdata elements"); } else { parser->current_rr.rdatas[parser->current_rr.rdata_count].data = data; ++parser->current_rr.rdata_count; } } /** * Used for TXT RR's to grow with undefined number of strings. */ void zadd_rdata_txt_wireformat(uint16_t *data, int first) { rdata_atom_type *rd; if (parser->current_rr.rdata_count >= MAXRDATALEN) { zc_error_prev_line("too many rdata txt elements"); return; } /* First STR in str_seq, allocate 65K in first unused rdata * else find last used rdata */ if (first) { rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count]; if ((rd->data = (uint16_t *) region_alloc(parser->rr_region, sizeof(uint16_t) + 65535 * sizeof(uint8_t))) == NULL) { zc_error_prev_line("Could not allocate memory for TXT RR"); return; } parser->current_rr.rdata_count++; rd->data[0] = 0; } else rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1]; if ((size_t)rd->data[0] + (size_t)data[0] > 65535) { zc_error_prev_line("too large rdata element"); return; } memcpy((uint8_t *)rd->data + 2 + rd->data[0], data + 1, data[0]); rd->data[0] += data[0]; } /** * Clean up after last call of zadd_rdata_txt_wireformat */ void zadd_rdata_txt_clean_wireformat() { uint16_t *tmp_data; rdata_atom_type *rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1]; if(!rd || !rd->data) return; /* previous syntax failure */ if ((tmp_data = (uint16_t *) region_alloc(parser->region, ((size_t)rd->data[0]) + ((size_t)2))) != NULL) { memcpy(tmp_data, rd->data, rd->data[0] + 2); /* rd->data of u16+65535 freed when rr_region is freed */ rd->data = tmp_data; } else { /* We could not get memory in non-volatile region */ zc_error_prev_line("could not allocate memory for rdata"); return; } } void zadd_rdata_domain(domain_type *domain) { if (parser->current_rr.rdata_count >= MAXRDATALEN) { zc_error_prev_line("too many rdata elements"); } else { parser->current_rr.rdatas[parser->current_rr.rdata_count].domain = domain; domain->usage ++; /* new reference to domain */ ++parser->current_rr.rdata_count; } } void parse_unknown_rdata(uint16_t type, uint16_t *wireformat) { buffer_type packet; uint16_t size; ssize_t rdata_count; ssize_t i; rdata_atom_type *rdatas; if (wireformat) { size = *wireformat; } else { return; } buffer_create_from(&packet, wireformat + 1, *wireformat); rdata_count = rdata_wireformat_to_rdata_atoms(parser->region, parser->db->domains, type, size, &packet, &rdatas); if (rdata_count == -1) { zc_error_prev_line("bad unknown RDATA"); return; } for (i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(type, i)) { zadd_rdata_domain(rdatas[i].domain); } else { zadd_rdata_wireformat(rdatas[i].data); } } region_recycle(parser->region, rdatas, rdata_count*sizeof(rdata_atom_type)); } /* * Compares two rdata arrays. * * Returns: * * zero if they are equal * non-zero if not * */ static int zrdatacmp(uint16_t type, rr_type *a, rr_type *b) { int i = 0; assert(a); assert(b); /* One is shorter than another */ if (a->rdata_count != b->rdata_count) return 1; /* Compare element by element */ for (i = 0; i < a->rdata_count; ++i) { if (rdata_atom_is_domain(type, i)) { if (rdata_atom_domain(a->rdatas[i]) != rdata_atom_domain(b->rdatas[i])) { return 1; } } else if(rdata_atom_is_literal_domain(type, i)) { if (rdata_atom_size(a->rdatas[i]) != rdata_atom_size(b->rdatas[i])) return 1; if (!dname_equal_nocase(rdata_atom_data(a->rdatas[i]), rdata_atom_data(b->rdatas[i]), rdata_atom_size(a->rdatas[i]))) return 1; } else { if (rdata_atom_size(a->rdatas[i]) != rdata_atom_size(b->rdatas[i])) { return 1; } if (memcmp(rdata_atom_data(a->rdatas[i]), rdata_atom_data(b->rdatas[i]), rdata_atom_size(a->rdatas[i])) != 0) { return 1; } } } /* Otherwise they are equal */ return 0; } /* * * Opens a zone file. * * Returns: * * - pointer to the parser structure * - NULL on error and errno set * */ static int zone_open(const char *filename, uint32_t ttl, uint16_t klass, const dname_type *origin) { /* Open the zone file... */ if (strcmp(filename, "-") == 0) { yyin = stdin; filename = ""; } else if (!(yyin = fopen(filename, "r"))) { return 0; } zparser_init(filename, ttl, klass, origin); return 1; } void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], uint16_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ uint8_t window = index / 256; uint8_t bit = index % 256; bits[window][bit / 8] |= (1 << (7 - bit % 8)); } static int has_soa(domain_type* domain) { rrset_type* p = NULL; if(!domain) return 0; for(p = domain->rrsets; p; p = p->next) if(rrset_rrtype(p) == TYPE_SOA) return 1; return 0; } int process_rr(void) { zone_type *zone = parser->current_zone; rr_type *rr = &parser->current_rr; rrset_type *rrset; size_t max_rdlength; int i; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rr->type); /* We only support IN class */ if (rr->klass != CLASS_IN) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("only class IN is supported"); else zc_error_prev_line("only class IN is supported"); return 0; } /* Make sure the maximum RDLENGTH does not exceed 65535 bytes. */ max_rdlength = rdata_maximum_wireformat_size( descriptor, rr->rdata_count, rr->rdatas); if (max_rdlength > MAX_RDLENGTH) { zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH); return 0; } /* we have the zone already */ assert(zone); if (rr->type == TYPE_SOA) { if (rr->owner != zone->apex) { zc_error_prev_line( "SOA record with invalid domain name"); return 0; } if(has_soa(rr->owner)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("this SOA record was already encountered"); else zc_error_prev_line("this SOA record was already encountered"); return 0; } rr->owner->is_apex = 1; } if (!domain_is_subdomain(rr->owner, zone->apex)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("out of zone data"); else zc_error_prev_line("out of zone data"); return 0; } /* Do we have this type of rrset already? */ rrset = domain_find_rrset(rr->owner, zone, rr->type); if (!rrset) { rrset = (rrset_type *) region_alloc(parser->region, sizeof(rrset_type)); rrset->zone = zone; rrset->rr_count = 1; rrset->rrs = (rr_type *) region_alloc(parser->region, sizeof(rr_type)); rrset->rrs[0] = *rr; /* Add it */ domain_add_rrset(rr->owner, rrset); } else { rr_type* o; if (rr->type != TYPE_RRSIG && rrset->rrs[0].ttl != rr->ttl) { zc_warning_prev_line( "%s TTL %u does not match the TTL %u of the %s RRset", domain_to_string(rr->owner), (unsigned)rr->ttl, (unsigned)rrset->rrs[0].ttl, rrtype_to_string(rr->type)); } /* Search for possible duplicates... */ for (i = 0; i < rrset->rr_count; i++) { if (!zrdatacmp(rr->type, rr, &rrset->rrs[i])) { break; } } /* Discard the duplicates... */ if (i < rrset->rr_count) { return 0; } if(rrset->rr_count == 65535) { zc_error_prev_line("too many RRs for domain RRset"); return 0; } /* Add it... */ o = rrset->rrs; rrset->rrs = (rr_type *) region_alloc_array(parser->region, (rrset->rr_count + 1), sizeof(rr_type)); memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type)); region_recycle(parser->region, o, (rrset->rr_count) * sizeof(rr_type)); rrset->rrs[rrset->rr_count] = *rr; ++rrset->rr_count; } if(rr->type == TYPE_DNAME && rrset->rr_count > 1) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("multiple DNAMEs at the same name"); else zc_error_prev_line("multiple DNAMEs at the same name"); } if(rr->type == TYPE_CNAME && rrset->rr_count > 1) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("multiple CNAMEs at the same name"); else zc_error_prev_line("multiple CNAMEs at the same name"); } if((rr->type == TYPE_DNAME && domain_find_rrset(rr->owner, zone, TYPE_CNAME)) ||(rr->type == TYPE_CNAME && domain_find_rrset(rr->owner, zone, TYPE_DNAME))) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("DNAME and CNAME at the same name"); else zc_error_prev_line("DNAME and CNAME at the same name"); } if(domain_find_rrset(rr->owner, zone, TYPE_CNAME) && domain_find_non_cname_rrset(rr->owner, zone)) { if(zone_is_slave(zone->opts)) zc_warning_prev_line("CNAME and other data at the same name"); else zc_error_prev_line("CNAME and other data at the same name"); } /* Check we have SOA */ if(rr->owner == zone->apex) apex_rrset_checks(parser->db, rrset, rr->owner); if(parser->line % ZONEC_PCT_COUNT == 0 && time(NULL) > startzonec + ZONEC_PCT_TIME) { struct stat buf; startzonec = time(NULL); buf.st_size = 0; fstat(fileno(yyin), &buf); if(buf.st_size == 0) buf.st_size = 1; VERBOSITY(1, (LOG_INFO, "parse %s %d %%", parser->current_zone->opts->name, (int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size))); } ++totalrrs; return 1; } /* * Find rrset type for any zone */ static rrset_type* domain_find_rrset_any(domain_type *domain, uint16_t type) { rrset_type *result = domain->rrsets; while (result) { if (rrset_rrtype(result) == type) { return result; } result = result->next; } return NULL; } /* * Check for DNAME type. Nothing is allowed below it */ static void check_dname(zone_type* zone) { domain_type* domain; for(domain = zone->apex; domain && domain_is_subdomain(domain, zone->apex); domain=domain_next(domain)) { if(domain->is_existing) { /* there may not be DNAMEs above it */ domain_type* parent = domain->parent; #ifdef NSEC3 if(domain_has_only_NSEC3(domain, NULL)) continue; #endif while(parent) { if(domain_find_rrset_any(parent, TYPE_DNAME)) { zc_error("While checking node %s,", domain_to_string(domain)); zc_error("DNAME at %s has data below it. " "This is not allowed (rfc 2672).", domain_to_string(parent)); return; } parent = parent->parent; } } } } /* * Reads the specified zone into the memory * nsd_options can be NULL if no config file is passed. */ unsigned int zonec_read(const char* name, const char* zonefile, zone_type* zone) { const dname_type *dname; totalrrs = 0; startzonec = time(NULL); parser->errors = 0; dname = dname_parse(parser->rr_region, name); if (!dname) { zc_error("incorrect zone name '%s'", name); return 1; } #ifndef ROOT_SERVER /* Is it a root zone? Are we a root server then? Idiot proof. */ if (dname->label_count == 1) { zc_error("not configured as a root server"); return 1; } #endif /* Open the zone file */ if (!zone_open(zonefile, 3600, CLASS_IN, dname)) { zc_error("cannot open '%s': %s", zonefile, strerror(errno)); return 1; } parser->current_zone = zone; /* Parse and process all RRs. */ yyparse(); /* remove origin if it was unused */ if(parser->origin != error_domain) domain_table_deldomain(parser->db, parser->origin); /* rr_region has been emptied by now */ dname = dname_parse(parser->rr_region, name); /* check if zone file contained a correct SOA record */ if (!parser->current_zone) { zc_error("zone configured as '%s' has no content.", name); } else if(!parser->current_zone->soa_rrset || parser->current_zone->soa_rrset->rr_count == 0) { zc_error("zone configured as '%s' has no SOA record.", name); } else if(dname_compare(domain_dname( parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) { zc_error("zone configured as '%s', but SOA has owner '%s'.", name, domain_to_string( parser->current_zone->soa_rrset->rrs[0].owner)); } region_free_all(parser->rr_region); parser_flush(); fclose(yyin); if(!zone_is_slave(zone->opts)) check_dname(zone); parser->filename = NULL; return parser->errors; } /* * setup parse */ void zonec_setup_parser(namedb_type* db) { region_type* rr_region = region_create(xalloc, free); parser = zparser_create(db->region, rr_region, db); assert(parser); /* Unique pointers used to mark errors. */ error_dname = (dname_type *) region_alloc(db->region, 1); error_domain = (domain_type *) region_alloc(db->region, 1); /* Open the network database */ setprotoent(1); setservent(1); } /** desetup parse */ void zonec_desetup_parser(void) { if(parser) { endservent(); endprotoent(); region_destroy(parser->rr_region); /* removed when parser->region(=db->region) is destroyed: * region_recycle(parser->region, (void*)error_dname, 1); * region_recycle(parser->region, (void*)error_domain, 1); */ /* clear memory for exit, but this is not portable to * other versions of lex. yylex_destroy(); */ #ifdef MEMCLEAN /* OS collects memory pages */ yylex_destroy(); #endif } } static domain_table_type* orig_domains = NULL; static region_type* orig_region = NULL; static region_type* orig_dbregion = NULL; /** setup for string parse */ void zonec_setup_string_parser(region_type* region, domain_table_type* domains) { assert(parser); /* global parser must be setup */ orig_domains = parser->db->domains; orig_region = parser->region; orig_dbregion = parser->db->region; parser->region = region; parser->db->region = region; parser->db->domains = domains; zparser_init("string", 3600, CLASS_IN, domain_dname(domains->root)); } /** desetup string parse */ void zonec_desetup_string_parser(void) { parser->region = orig_region; parser->db->domains = orig_domains; parser->db->region = orig_dbregion; } /** parse a string into temporary storage */ int zonec_parse_string(region_type* region, domain_table_type* domains, zone_type* zone, char* str, domain_type** parsed, int* num_rrs) { int errors; zonec_setup_string_parser(region, domains); parser->current_zone = zone; parser->errors = 0; totalrrs = 0; startzonec = time(NULL)+100000; /* disable */ parser_push_stringbuf(str); yyparse(); parser_pop_stringbuf(); errors = parser->errors; *num_rrs = totalrrs; if(*num_rrs == 0) *parsed = NULL; else *parsed = parser->prev_dname; /* remove origin if it was not used during the parse */ if(parser->origin != error_domain) domain_table_deldomain(parser->db, parser->origin); region_free_all(parser->rr_region); zonec_desetup_string_parser(); parser_flush(); return errors; } nsd-4.1.26/axfr.c0000664000175000017500000001310113135363374013136 0ustar wouterwouter/* * axfr.c -- generating AXFR responses. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include "axfr.h" #include "dns.h" #include "packet.h" #include "options.h" #define AXFR_TSIG_SIGN_EVERY_NTH 96 /* tsig sign every N packets. */ query_state_type query_axfr(struct nsd *nsd, struct query *query) { domain_type *closest_match; domain_type *closest_encloser; int exact; int added; uint16_t total_added = 0; if (query->axfr_is_done) return QUERY_PROCESSED; if (query->maxlen > AXFR_MAX_MESSAGE_LEN) query->maxlen = AXFR_MAX_MESSAGE_LEN; assert(!query_overflow(query)); /* only keep running values for most packets */ query->tsig_prepare_it = 0; query->tsig_update_it = 1; if(query->tsig_sign_it) { /* prepare for next updates */ query->tsig_prepare_it = 1; query->tsig_sign_it = 0; } if (query->axfr_zone == NULL) { domain_type* qdomain; /* Start AXFR. */ STATUP(nsd, raxfr); exact = namedb_lookup(nsd->db, query->qname, &closest_match, &closest_encloser); qdomain = closest_encloser; query->axfr_zone = domain_find_zone(nsd->db, closest_encloser); if (!exact || query->axfr_zone == NULL || query->axfr_zone->apex != qdomain || query->axfr_zone->soa_rrset == NULL) { /* No SOA no transfer */ RCODE_SET(query->packet, RCODE_NOTAUTH); return QUERY_PROCESSED; } ZTATUP(nsd, query->axfr_zone, raxfr); query->axfr_current_domain = qdomain; query->axfr_current_rrset = NULL; query->axfr_current_rr = 0; if(query->tsig.status == TSIG_OK) { query->tsig_sign_it = 1; /* sign first packet in stream */ } query_add_compression_domain(query, qdomain, QHEADERSZ); assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (!added) { /* XXX: This should never happen... generate error code? */ abort(); } ++total_added; } else { /* * Query name and EDNS need not be repeated after the * first response packet. */ query->edns.status = EDNS_NOT_PRESENT; buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); query_prepare_response(query); } /* Add zone RRs until answer is full. */ while (query->axfr_current_domain != NULL && domain_is_subdomain(query->axfr_current_domain, query->axfr_zone->apex)) { if (!query->axfr_current_rrset) { query->axfr_current_rrset = domain_find_any_rrset( query->axfr_current_domain, query->axfr_zone); query->axfr_current_rr = 0; } while (query->axfr_current_rrset) { if (query->axfr_current_rrset != query->axfr_zone->soa_rrset && query->axfr_current_rrset->zone == query->axfr_zone) { while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { added = packet_encode_rr( query, query->axfr_current_domain, &query->axfr_current_rrset->rrs[query->axfr_current_rr], query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); if (!added) goto return_answer; ++total_added; ++query->axfr_current_rr; } } query->axfr_current_rrset = query->axfr_current_rrset->next; query->axfr_current_rr = 0; } assert(query->axfr_current_domain); query->axfr_current_domain = domain_next(query->axfr_current_domain); } /* Add terminating SOA RR. */ assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (added) { ++total_added; query->tsig_sign_it = 1; /* sign last packet */ query->axfr_is_done = 1; } return_answer: AA_SET(query->packet); ANCOUNT_SET(query->packet, total_added); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); /* check if it needs tsig signatures */ if(query->tsig.status == TSIG_OK) { if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { query->tsig_sign_it = 1; } } query_clear_compression_tables(query); return QUERY_IN_AXFR; } /* * Answer if this is an AXFR or IXFR query. */ query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q) { struct acl_options *acl = NULL; /* Is it AXFR? */ switch (q->qtype) { case TYPE_AXFR: if (q->tcp) { struct zone_options* zone_opt; zone_opt = zone_options_find(nsd->options, q->qname); if(!zone_opt || acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) { if (verbosity >= 2) { char a[128]; addr2str(&q->addr, a, sizeof(a)); VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s", dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", acl?"blocked":"no acl matches")); if (!zone_opt) { RCODE_SET(q->packet, RCODE_NOTAUTH); } else { RCODE_SET(q->packet, RCODE_REFUSE); } return QUERY_PROCESSED; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); if (verbosity >= 1) { char a[128]; addr2str(&q->addr, a, sizeof(a)); VERBOSITY(1, (LOG_INFO, "%s for %s from %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a)); } 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; default: return QUERY_DISCARDED; } } nsd-4.1.26/nsec3.c0000664000175000017500000010612413345752552013224 0ustar wouterwouter/* * nsec3.c -- nsec3 handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #ifdef NSEC3 #include #include #include "nsec3.h" #include "iterated_hash.h" #include "namedb.h" #include "nsd.h" #include "answer.h" #include "udbzone.h" #include "options.h" #define NSEC3_RDATA_BITMAP 5 /* compare nsec3 hashes in nsec3 tree */ static int cmp_hash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; 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 */ static int cmp_wchash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; 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 */ static int cmp_dshash_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; if(!a->nsec3) return (b->nsec3?-1:0); if(!b->nsec3) return 1; 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 * stored in the domain name of the node */ static int cmp_nsec3_tree(const void* x, const void* y) { const domain_type* a = (const domain_type*)x; const domain_type* b = (const domain_type*)y; /* labelcount + 32long label */ assert(dname_name(domain_dname_const(a))[0] == 32); assert(dname_name(domain_dname_const(b))[0] == 32); return memcmp(dname_name(domain_dname_const(a)), dname_name(domain_dname_const(b)), 33); } void nsec3_zone_trees_create(struct region* region, zone_type* zone) { if(!zone->nsec3tree) zone->nsec3tree = rbtree_create(region, cmp_nsec3_tree); if(!zone->hashtree) zone->hashtree = rbtree_create(region, cmp_hash_tree); if(!zone->wchashtree) zone->wchashtree = rbtree_create(region, cmp_wchash_tree); if(!zone->dshashtree) zone->dshashtree = rbtree_create(region, cmp_dshash_tree); } static void detect_nsec3_params(rr_type* nsec3_apex, const unsigned char** salt, int* salt_len, int* iter) { assert(salt && salt_len && iter); assert(nsec3_apex); *salt_len = rdata_atom_data(nsec3_apex->rdatas[3])[0]; *salt = (unsigned char*)(rdata_atom_data(nsec3_apex->rdatas[3])+1); *iter = read_uint16(rdata_atom_data(nsec3_apex->rdatas[2])); } const dname_type * nsec3_b32_create(region_type* region, zone_type* zone, unsigned char* hash) { const dname_type* dname; char b32[SHA_DIGEST_LENGTH*2+1]; b32_ntop(hash, SHA_DIGEST_LENGTH, b32, sizeof(b32)); dname=dname_parse(region, b32); dname=dname_concatenate(region, dname, domain_dname(zone->apex)); return dname; } void nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store) { const unsigned char* nsec3_salt = NULL; int nsec3_saltlength = 0; int nsec3_iterations = 0; detect_nsec3_params(zone->nsec3_param, &nsec3_salt, &nsec3_saltlength, &nsec3_iterations); iterated_hash((unsigned char*)store, nsec3_salt, nsec3_saltlength, dname_name(dname), dname->name_size, nsec3_iterations); } #define STORE_HASH(x,y) memmove(domain->nsec3->x,y,NSEC3_HASH_LEN); domain->nsec3->have_##x =1; /** find hash or create it and store it */ static void 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->hash_wc) { return; } /* lookup failed; disk failure or so */ 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->hash_wc->wc.hash); } static void nsec3_lookup_hash_ds(region_type* region, zone_type* zone, const dname_type* dname, domain_type* domain) { if(domain->nsec3->ds_parent_hash) { return; } /* lookup failed; disk failure or so */ 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 nsec3_has_soa(rr_type* rr) { if(rdata_atom_size(rr->rdatas[NSEC3_RDATA_BITMAP]) >= 3 && /* has types in bitmap */ rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP])[0] == 0 && /* first window = 0, */ /* [1]: bitmap length must be >= 1 */ /* [2]: bit[6] = SOA, thus mask first bitmap octet with 0x02 */ rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP])[2]&0x02) { /* SOA bit set */ return 1; } return 0; } static rr_type* check_apex_soa(namedb_type* namedb, zone_type *zone, int nolog) { uint8_t h[NSEC3_HASH_LEN]; domain_type* domain; const dname_type* hashed_apex, *dname = domain_dname(zone->apex); unsigned j; rrset_type* nsec3_rrset; region_type* tmpregion; nsec3_hash_and_store(zone, dname, h); tmpregion = region_create(xalloc, free); hashed_apex = nsec3_b32_create(tmpregion, zone, h); domain = domain_table_find(namedb->domains, hashed_apex); if(!domain) { if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry has no hash(apex).", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); if(!nsec3_rrset) { if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } for(j=0; jrr_count; j++) { if(nsec3_has_soa(&nsec3_rrset->rrs[j])) { region_destroy(tmpregion); return &nsec3_rrset->rrs[j]; } } if(!nolog) { log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.", domain_to_string(zone->apex)); log_msg(LOG_ERR, "hash(apex)= %s", dname_to_string(hashed_apex, NULL)); } region_destroy(tmpregion); return NULL; } static void nsec3param_to_str(struct rr* rr, char* str, size_t buflen) { rdata_atom_type* rd = rr->rdatas; size_t len; len = snprintf(str, buflen, "%u %u %u ", (unsigned)rdata_atom_data(rd[0])[0], (unsigned)rdata_atom_data(rd[1])[0], (unsigned)read_uint16(rdata_atom_data(rd[2]))); if(rdata_atom_data(rd[3])[0] == 0) { if(buflen > len + 2) str[len++] = '-'; } else { len += hex_ntop(rdata_atom_data(rd[3])+1, rdata_atom_data(rd[3])[0], str+len, buflen-len-1); } if(buflen > len + 1) str[len] = 0; } static struct rr* db_find_nsec3param(struct namedb* db, struct zone* z, struct rr* avoid_rr, int checkchain) { unsigned i; rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); if(!rrset) /* no NSEC3PARAM in mem */ return NULL; /* find first nsec3param we can support (SHA1, no flags) */ for(i=0; irr_count; i++) { rdata_atom_type* rd = rrset->rrs[i].rdatas; /* do not use the RR that is going to be deleted (in IXFR) */ if(&rrset->rrs[i] == avoid_rr) continue; if(rrset->rrs[i].rdata_count < 4) continue; if(rdata_atom_data(rd[0])[0] == NSEC3_SHA1_HASH && rdata_atom_data(rd[1])[0] == 0) { if(checkchain) { z->nsec3_param = &rrset->rrs[i]; if(!check_apex_soa(db, z, 1)) { char str[MAX_RDLENGTH*2+16]; nsec3param_to_str(z->nsec3_param, str, sizeof(str)); VERBOSITY(1, (LOG_WARNING, "zone %s NSEC3PARAM %s has broken chain, ignoring", domain_to_string(z->apex), str)); continue; /* don't use broken chain */ } } if(2 <= verbosity) { char str[MAX_RDLENGTH*2+16]; nsec3param_to_str(&rrset->rrs[i], str, sizeof(str)); VERBOSITY(2, (LOG_INFO, "rehash of zone %s with parameters %s", domain_to_string(z->apex), str)); } return &rrset->rrs[i]; } } return NULL; } static struct rr* udb_zone_find_nsec3param(struct namedb* db, udb_base* udb, udb_ptr* uz, struct zone* z, int checkchain) { udb_ptr urr; unsigned i; rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); if(!rrset) /* no NSEC3PARAM in mem */ return NULL; udb_ptr_new(&urr, udb, &ZONE(uz)->nsec3param); if(!urr.data || RR(&urr)->len < 5) { /* no NSEC3PARAM in udb */ udb_ptr_unlink(&urr, udb); return NULL; } /* find matching NSEC3PARAM RR in memory */ for(i=0; irr_count; i++) { /* if this RR matches the udb RR then we are done */ rdata_atom_type* rd = rrset->rrs[i].rdatas; if(rrset->rrs[i].rdata_count < 4) continue; if(RR(&urr)->wire[0] == rdata_atom_data(rd[0])[0] && /*alg*/ RR(&urr)->wire[1] == rdata_atom_data(rd[1])[0] && /*flg*/ RR(&urr)->wire[2] == rdata_atom_data(rd[2])[0] && /*iter*/ RR(&urr)->wire[3] == rdata_atom_data(rd[2])[1] && RR(&urr)->wire[4] == rdata_atom_data(rd[3])[0] && /*slen*/ RR(&urr)->len >= 5 + RR(&urr)->wire[4] && memcmp(RR(&urr)->wire+5, rdata_atom_data(rd[3])+1, rdata_atom_data(rd[3])[0]) == 0) { udb_ptr_unlink(&urr, udb); if(checkchain) { z->nsec3_param = &rrset->rrs[i]; if(!check_apex_soa(db, z, 1)) return db_find_nsec3param(db, z, NULL, checkchain); } return &rrset->rrs[i]; } } udb_ptr_unlink(&urr, udb); return NULL; } void nsec3_find_zone_param(struct namedb* db, struct zone* zone, udb_ptr* z, struct rr* avoid_rr, int checkchain) { /* get nsec3param RR from udb */ if(db->udb) zone->nsec3_param = udb_zone_find_nsec3param(db, db->udb, z, zone, checkchain); /* no db, get from memory, avoid using the rr that is going to be * deleted, avoid_rr */ else zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, checkchain); } /* check params ok for one RR */ static int nsec3_rdata_params_ok(rdata_atom_type* prd, rdata_atom_type* rd) { return (rdata_atom_data(rd[0])[0] == rdata_atom_data(prd[0])[0] && /* hash algo */ rdata_atom_data(rd[2])[0] == rdata_atom_data(prd[2])[0] && /* iterations 0 */ rdata_atom_data(rd[2])[1] == rdata_atom_data(prd[2])[1] && /* iterations 1 */ rdata_atom_data(rd[3])[0] == rdata_atom_data(prd[3])[0] && /* salt length */ memcmp(rdata_atom_data(rd[3])+1, rdata_atom_data(prd[3])+1, rdata_atom_data(rd[3])[0]) == 0 ); } int nsec3_rr_uses_params(rr_type* rr, zone_type* zone) { if(!rr || rr->rdata_count < 4) return 0; return nsec3_rdata_params_ok(zone->nsec3_param->rdatas, rr->rdatas); } int nsec3_in_chain_count(domain_type* domain, zone_type* zone) { rrset_type* rrset = domain_find_rrset(domain, zone, TYPE_NSEC3); unsigned i; int count = 0; if(!rrset || !zone->nsec3_param) return 0; /* no NSEC3s, none in the chain */ for(i=0; irr_count; i++) { if(nsec3_rr_uses_params(&rrset->rrs[i], zone)) count++; } return count; } struct domain* nsec3_chain_find_prev(struct zone* zone, struct domain* domain) { if(domain->nsec3 && domain->nsec3->nsec3_node.key) { /* see if there is a prev */ rbnode_type* r = rbtree_previous(&domain->nsec3->nsec3_node); if(r != RBTREE_NULL) { /* found a previous, which is not the root-node in * the prehash tree (and thus points to the tree) */ return (domain_type*)r->key; } } if(zone->nsec3_last) return zone->nsec3_last; return NULL; } void nsec3_clear_precompile(struct namedb* db, zone_type* zone) { domain_type* walk; /* clear prehash items (there must not be items for other zones) */ prehash_clear(db->domains); /* clear trees */ hash_tree_clear(zone->nsec3tree); hash_tree_clear(zone->hashtree); hash_tree_clear(zone->wchashtree); hash_tree_clear(zone->dshashtree); /* wipe hashes */ /* wipe precompile */ walk = zone->apex; while(walk && domain_is_subdomain(walk, zone->apex)) { if(walk->nsec3) { if(nsec3_condition_hash(walk, zone)) { walk->nsec3->nsec3_node.key = NULL; walk->nsec3->nsec3_cover = NULL; walk->nsec3->nsec3_wcard_child_cover = NULL; walk->nsec3->nsec3_is_exact = 0; 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(nsec3_condition_dshash(walk, zone)) { walk->nsec3->nsec3_ds_parent_cover = NULL; walk->nsec3->nsec3_ds_parent_is_exact = 0; 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); } zone->nsec3_last = NULL; } /* see if domain name is part of (existing names in) the nsec3 zone */ int nsec3_domain_part_of_zone(domain_type* d, zone_type* z) { while(d) { if(d->is_apex) return (z->apex == d); /* zonecut, if right zone*/ d = d->parent; } return 0; } /* condition when a domain is precompiled */ int nsec3_condition_hash(domain_type* d, zone_type* z) { return d->is_existing && !domain_has_only_NSEC3(d, z) && nsec3_domain_part_of_zone(d, z) && !domain_is_glue(d, z); } /* condition when a domain is ds precompiled */ int nsec3_condition_dshash(domain_type* d, zone_type* z) { return d->is_existing && !domain_has_only_NSEC3(d, z) && (domain_find_rrset(d, z, TYPE_DS) || domain_find_rrset(d, z, TYPE_NS)) && d != z->apex && nsec3_domain_part_of_zone(d->parent, z); } zone_type* nsec3_tree_zone(namedb_type* db, domain_type* d) { /* see nsec3_domain_part_of_zone; domains part of zone that has * apex above them */ /* this does not use the rrset->zone pointer because there may be * no rrsets left at apex (no SOA), e.g. during IXFR */ while(d) { if(d->is_apex) { /* we can try a SOA if its present (faster than tree)*/ /* DNSKEY and NSEC3PARAM are also good indicators */ rrset_type *rrset; for (rrset = d->rrsets; rrset; rrset = rrset->next) if (rrset_rrtype(rrset) == TYPE_SOA || rrset_rrtype(rrset) == TYPE_DNSKEY || rrset_rrtype(rrset) == TYPE_NSEC3PARAM) return rrset->zone; return namedb_find_zone(db, domain_dname(d)); } d = d->parent; } return NULL; } zone_type* nsec3_tree_dszone(namedb_type* db, domain_type* d) { /* the DStree does not contain nodes with d==z->apex */ if(d->is_apex) d = d->parent; return nsec3_tree_zone(db, d); } int nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t hashlen, domain_type** result) { rbnode_type* r = NULL; int exact; domain_type d; uint8_t n[48]; /* nsec3tree is sorted by b32 encoded domain name of the NSEC3 */ b32_ntop(hash, hashlen, (char*)(n+5), sizeof(n)-5); #ifdef USE_RADIX_TREE d.dname = (dname_type*)n; #else d.node.key = n; #endif n[0] = 34; /* name_size */ n[1] = 2; /* label_count */ n[2] = 0; /* label_offset[0] */ n[3] = 0; /* label_offset[1] */ n[4] = 32; /* label-size[0] */ assert(result); assert(zone->nsec3_param && zone->nsec3tree); exact = rbtree_find_less_equal(zone->nsec3tree, &d, &r); if(r) { *result = (domain_type*)r->key; } else { *result = zone->nsec3_last; } return exact; } void nsec3_precompile_domain(struct namedb* db, struct domain* domain, struct zone* zone, region_type* tmpregion) { domain_type* result = 0; int exact; allocate_domain_nsec3(db->domains, domain); /* hash it */ 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_wc->hash.node); zone_add_domain_in_hash_tree(db->region, &zone->wchashtree, cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node); /* lookup in tree cover ptr (or exact) */ 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 */ (void)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; } void nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain, struct zone* zone) { domain_type* result = 0; int exact; allocate_domain_nsec3(db->domains, domain); /* hash it : it could have different hash parameters then the other hash for this domain name */ 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->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->ds_parent_hash->node); } static void parse_nsec3_name(const dname_type* dname, uint8_t* hash, size_t buflen) { /* first label must be the match, */ size_t lablen = (buflen-1) * 8 / 5; const uint8_t* wire = dname_name(dname); assert(lablen == 32 && buflen == NSEC3_HASH_LEN+1); /* labels of length 32 for SHA1, and must have space+1 for convert */ if(wire[0] != lablen) { /* not NSEC3 */ memset(hash, 0, buflen); return; } (void)b32_pton((char*)wire+1, hash, buflen); } void nsec3_precompile_nsec3rr(namedb_type* db, struct domain* domain, struct zone* zone) { allocate_domain_nsec3(db->domains, domain); /* add into nsec3tree */ zone_add_domain_in_hash_tree(db->region, &zone->nsec3tree, cmp_nsec3_tree, domain, &domain->nsec3->nsec3_node); /* fixup the last in the zone */ if(rbtree_last(zone->nsec3tree)->key == domain) { zone->nsec3_last = domain; } } void nsec3_precompile_newparam(namedb_type* db, zone_type* zone) { region_type* tmpregion = region_create(xalloc, free); domain_type* walk; time_t s = time(NULL); unsigned long n = 0, c = 0; /* add nsec3s of chain to nsec3tree */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk = domain_next(walk)) { n++; if(nsec3_in_chain_count(walk, zone) != 0) { nsec3_precompile_nsec3rr(db, walk, zone); } } /* hash and precompile zone */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); walk = domain_next(walk)) { if(nsec3_condition_hash(walk, zone)) { nsec3_precompile_domain(db, walk, zone, tmpregion); region_free_all(tmpregion); } if(nsec3_condition_dshash(walk, zone)) nsec3_precompile_domain_ds(db, walk, zone); if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > s + ZONEC_PCT_TIME) { s = time(NULL); VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%", zone->opts->name, (int)(c*((unsigned long)100)/n))); } } region_destroy(tmpregion); } void prehash_zone_complete(struct namedb* db, struct zone* zone) { udb_ptr udbz; /* robust clear it */ nsec3_clear_precompile(db, zone); /* find zone settings */ assert(db && zone); udbz.data = 0; if(db->udb) { if(!udb_zone_search(db->udb, &udbz, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size)) { udb_ptr_init(&udbz, db->udb); /* zero the ptr */ } } nsec3_find_zone_param(db, zone, &udbz, NULL, 1); if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; if(udbz.data) udb_ptr_unlink(&udbz, db->udb); return; } if(udbz.data) udb_ptr_unlink(&udbz, db->udb); nsec3_precompile_newparam(db, zone); } static void init_lookup_key_hash_tree(domain_type* d, uint8_t* hash) { 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->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); } static void init_lookup_key_ds_tree(domain_type* d, uint8_t* hash) { 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 process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p, void (*init)(domain_type*, uint8_t*)) { 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)) { /* found an exact match */ return 1; } if(!*p) /* before first, go from first */ *p = rbtree_first(tree); /* the inexact, smaller, match we found, does not itself need to * be edited */ else *p = rbtree_next(*p); /* if this becomes NULL, nothing to do */ return 0; } /* set end pointer if possible */ static void process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p, void (*init)(domain_type*, uint8_t*)) { 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)) { /* an exact match, fine, because this one does not get * processed */ return; } /* inexact element, but if NULL, until first element in tree */ if(!*p) { *p = rbtree_first(tree); return; } /* inexact match, use next element, if possible, the smaller * element is part of the range */ *p = rbtree_next(*p); /* if next returns null, we go until the end of the tree */ } /* prehash domains in hash range start to end */ static void process_range(zone_type* zone, domain_type* start, domain_type* end, domain_type* nsec3) { /* start NULL means from first in tree */ /* end NULL means to last in tree */ rbnode_type *p = RBTREE_NULL, *pwc = RBTREE_NULL, *pds = RBTREE_NULL; rbnode_type *p_end = RBTREE_NULL, *pwc_end = RBTREE_NULL, *pds_end = RBTREE_NULL; /* because the nodes are on the prehashlist, the domain->nsec3 is * already allocated, and we need not allocate it here */ /* set start */ if(start) { uint8_t hash[NSEC3_HASH_LEN+1]; parse_nsec3_name(domain_dname(start), hash, sizeof(hash)); /* if exact match on first, set is_exact */ if(process_first(zone->hashtree, hash, &p, init_lookup_key_hash_tree)) { ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 1; p = rbtree_next(p); } (void)process_first(zone->wchashtree, hash, &pwc, init_lookup_key_wc_tree); if(process_first(zone->dshashtree, hash, &pds, init_lookup_key_ds_tree)){ ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_cover = nsec3; ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_is_exact = 1; pds = rbtree_next(pds); } } else { if(zone->hashtree) p = rbtree_first(zone->hashtree); if(zone->wchashtree) pwc = rbtree_first(zone->wchashtree); if(zone->dshashtree) pds = rbtree_first(zone->dshashtree); } /* set end */ if(end) { uint8_t hash[NSEC3_HASH_LEN+1]; parse_nsec3_name(domain_dname(end), hash, sizeof(hash)); process_end(zone->hashtree, hash, &p_end, init_lookup_key_hash_tree); process_end(zone->wchashtree, hash, &pwc_end, init_lookup_key_wc_tree); process_end(zone->dshashtree, hash, &pds_end, init_lookup_key_ds_tree); } /* precompile */ while(p != RBTREE_NULL && p != p_end) { ((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3; ((domain_type*)(p->key))->nsec3->nsec3_is_exact = 0; p = rbtree_next(p); } while(pwc != RBTREE_NULL && pwc != pwc_end) { ((domain_type*)(pwc->key))->nsec3-> nsec3_wcard_child_cover = nsec3; pwc = rbtree_next(pwc); } while(pds != RBTREE_NULL && pds != pds_end) { ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_cover = nsec3; ((domain_type*)(pds->key))->nsec3-> nsec3_ds_parent_is_exact = 0; pds = rbtree_next(pds); } } /* prehash a domain from the prehash list */ static void process_prehash_domain(domain_type* domain, zone_type* zone) { /* in the hashtree, wchashtree, dshashtree walk through to next NSEC3 * and set precompile pointers to point to this domain (or is_exact), * the first domain can be is_exact. If it is the last NSEC3, also * process the initial part (before the first) */ rbnode_type* nx; /* this domain is part of the prehash list and therefore the * domain->nsec3 is allocated and need not be allocated here */ assert(domain->nsec3 && domain->nsec3->nsec3_node.key); nx = rbtree_next(&domain->nsec3->nsec3_node); if(nx != RBTREE_NULL) { /* process until next nsec3 */ domain_type* end = (domain_type*)nx->key; process_range(zone, domain, end, domain); } else { /* first is root, but then comes the first nsec3 */ domain_type* first = (domain_type*)(rbtree_first( zone->nsec3tree)->key); /* last in zone */ process_range(zone, domain, NULL, domain); /* also process before first in zone */ process_range(zone, NULL, first, domain); } } void prehash_zone(struct namedb* db, struct zone* zone) { domain_type* d; if(!zone->nsec3_param) { prehash_clear(db->domains); return; } if(!check_apex_soa(db, zone, 1)) { /* the zone fails apex soa check, prehash complete may * detect other valid chains */ prehash_clear(db->domains); prehash_zone_complete(db, zone); return; } /* process prehash list */ for(d = db->domains->prehash_list; d; d = d->nsec3->prehash_next) { process_prehash_domain(d, zone); } /* clear prehash list */ prehash_clear(db->domains); if(!check_apex_soa(db, zone, 0)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; } } /* add the NSEC3 rrset to the query answer at the given domain */ static void nsec3_add_rrset(struct query* query, struct answer* answer, rr_section_type section, struct domain* domain) { if(domain) { rrset_type* rrset = domain_find_rrset(domain, query->zone, TYPE_NSEC3); if(rrset) answer_add_rrset(answer, section, domain, rrset); } } /* this routine does hashing at query-time. slow. */ static void nsec3_add_nonexist_proof(struct query* query, struct answer* answer, struct domain* encloser, const dname_type* qname) { uint8_t hash[NSEC3_HASH_LEN]; const dname_type* to_prove; domain_type* cover=0; assert(encloser); /* if query=a.b.c.d encloser=c.d. then proof needed for b.c.d. */ /* if query=a.b.c.d encloser=*.c.d. then proof needed for b.c.d. */ to_prove = dname_partial_copy(query->region, qname, dname_label_match_count(qname, domain_dname(encloser))+1); /* generate proof that one label below closest encloser does not exist */ nsec3_hash_and_store(query->zone, to_prove, hash); 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 hash=%s reverse=%s", dname_to_string(to_prove, NULL), hashbuf, reversebuf)); RCODE_SET(query->packet, RCODE_SERVFAIL); return; } else { /* cover proves the qname does not exist */ nsec3_add_rrset(query, answer, AUTHORITY_SECTION, cover); } } static void nsec3_add_closest_encloser_proof( struct query* query, struct answer* answer, struct domain* closest_encloser, const dname_type* qname) { if(!closest_encloser) return; /* prove that below closest encloser nothing exists */ nsec3_add_nonexist_proof(query, answer, closest_encloser, qname); /* proof that closest encloser exists */ if(closest_encloser->nsec3 && closest_encloser->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover); } void nsec3_answer_wildcard(struct query *query, struct answer *answer, struct domain *wildcard, const dname_type* qname) { if(!wildcard) return; if(!query->zone->nsec3_param) return; nsec3_add_nonexist_proof(query, answer, wildcard, qname); } static void nsec3_add_ds_proof(struct query *query, struct answer *answer, struct domain *domain, int delegpt) { /* assert we are above the zone cut */ assert(domain != query->zone->apex); if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) { /* use NSEC3 record from above the zone cut. */ nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_ds_parent_cover); } else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact && nsec3_domain_part_of_zone(domain->nsec3->nsec3_cover, query->zone)) { nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_cover); } else { /* prove closest provable encloser */ domain_type* par = domain->parent; domain_type* prev_par = 0; while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact)) { prev_par = par; par = par->parent; } assert(par); /* parent zone apex must be provable, thus this ends */ if(!par->nsec3) return; nsec3_add_rrset(query, answer, AUTHORITY_SECTION, par->nsec3->nsec3_cover); /* we took several steps to go to the provable parent, so the one below it has no exact nsec3, disprove it. disprove is easy, it has a prehashed cover ptr. */ if(prev_par && prev_par->nsec3) { assert(prev_par != domain && !prev_par->nsec3->nsec3_is_exact); nsec3_add_rrset(query, answer, AUTHORITY_SECTION, prev_par->nsec3->nsec3_cover); } /* add optout range from parent zone */ /* note: no check of optout bit, resolver checks it */ if(domain->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, domain->nsec3->nsec3_ds_parent_cover); } } void nsec3_answer_nodata(struct query* query, struct answer* answer, struct domain* original) { if(!query->zone->nsec3_param) return; /* nodata when asking for secure delegation */ if(query->qtype == TYPE_DS) { if(original == query->zone->apex) { /* DS at zone apex, but server not authoritative for parent zone */ /* so answer at the child zone level */ if(original->nsec3 && original->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); return; } /* query->zone must be the parent zone */ nsec3_add_ds_proof(query, answer, original, 0); } /* the nodata is result from a wildcard match */ else if (original==original->wildcard_child_closest_match && label_is_wildcard(dname_name(domain_dname(original)))) { /* denial for wildcard is already there */ /* add parent proof to have a closest encloser proof for wildcard parent */ /* in other words: nsec3 matching closest encloser */ if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->parent->nsec3->nsec3_cover); /* proof for wildcard itself */ /* in other words: nsec3 matching source of synthesis */ if(original->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); } else { /* add nsec3 to prove rrset does not exist */ if(original->nsec3) { if(!original->nsec3->nsec3_is_exact) { /* go up to an existing parent */ while(original->parent && original->parent->nsec3 && !original->parent->nsec3->nsec3_is_exact) original = original->parent; } nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->nsec3->nsec3_cover); if(!original->nsec3->nsec3_is_exact) { if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, original->parent->nsec3->nsec3_cover); } } } } void nsec3_answer_delegation(struct query *query, struct answer *answer) { if(!query->zone->nsec3_param) return; nsec3_add_ds_proof(query, answer, query->delegation_domain, 1); } int domain_has_only_NSEC3(struct domain* domain, struct zone* zone) { /* check for only NSEC3/RRSIG */ rrset_type* rrset = domain->rrsets; int nsec3_seen = 0; while(rrset) { if(!zone || rrset->zone == zone) { if(rrset->rrs[0].type == TYPE_NSEC3) nsec3_seen = 1; else if(rrset->rrs[0].type != TYPE_RRSIG) return 0; } rrset = rrset->next; } return nsec3_seen; } void nsec3_answer_authoritative(struct domain** match, struct query *query, struct answer *answer, struct domain* closest_encloser, const dname_type* qname) { if(!query->zone->nsec3_param) return; assert(match); /* there is a match, this has 1 RRset, which is NSEC3, but qtype is not. */ /* !is_existing: no RR types exist at the QNAME, nor at any descendant of QNAME */ if(*match && !(*match)->is_existing && #if 0 query->qtype != TYPE_NSEC3 && #endif domain_has_only_NSEC3(*match, query->zone)) { /* act as if the NSEC3 domain did not exist, name error */ *match = 0; /* all nsec3s are directly below the apex, that is closest encloser */ if(query->zone->apex->nsec3 && query->zone->apex->nsec3->nsec3_is_exact) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex->nsec3->nsec3_cover); /* disprove the nsec3 record. */ if(closest_encloser->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover); /* disprove a wildcard */ if(query->zone->apex->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex->nsec3->nsec3_wcard_child_cover); if (domain_wildcard_child(query->zone->apex)) { /* wildcard exists below the domain */ /* wildcard and nsec3 domain clash. server failure. */ RCODE_SET(query->packet, RCODE_SERVFAIL); } return; } else if(*match && (*match)->is_existing && #if 0 query->qtype != TYPE_NSEC3 && #endif (domain_has_only_NSEC3(*match, query->zone) || !domain_find_any_rrset(*match, query->zone))) { /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */ nsec3_answer_nodata(query, answer, *match); return; } if(!*match) { /* name error, domain does not exist */ nsec3_add_closest_encloser_proof(query, answer, closest_encloser, qname); if(closest_encloser->nsec3) nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_wcard_child_cover); } } #endif /* NSEC3 */ nsd-4.1.26/query.h0000664000175000017500000001172213270314251013345 0ustar wouterwouter/* * query.h -- manipulation with the queries * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _QUERY_H_ #define _QUERY_H_ #include #include #include "namedb.h" #include "nsd.h" #include "packet.h" #include "tsig.h" enum query_state { QUERY_PROCESSED, QUERY_DISCARDED, QUERY_IN_AXFR }; typedef enum query_state query_state_type; /* Query as we pass it around */ typedef struct query query_type; struct query { /* * Memory region freed whenever the query is reset. */ region_type *region; /* * The address the query was received from. */ #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; /* * Maximum supported query size. */ size_t maxlen; /* * Space reserved for optional records like EDNS. */ size_t reserved_space; /* EDNS information provided by the client. */ edns_record_type edns; /* TSIG record information and running hash for query-response */ tsig_record_type tsig; /* tsig actions can be overridden, for axfr transfer. */ int tsig_prepare_it, tsig_update_it, tsig_sign_it; int tcp; uint16_t tcplen; buffer_type *packet; /* Normalized query domain name. */ const dname_type *qname; /* Query type and class in host byte order. */ uint16_t qtype; uint16_t qclass; /* The zone used to answer the query. */ zone_type *zone; /* The delegation domain, if any. */ domain_type *delegation_domain; /* The delegation NS rrset, if any. */ rrset_type *delegation_rrset; /* Original opcode. */ uint8_t opcode; /* * The number of CNAMES followed. After a CNAME is followed * we no longer change the RCODE to NXDOMAIN and no longer add * SOA records to the authority section in case of NXDOMAIN * and NODATA. * Also includes number of DNAMES followed. */ int cname_count; /* Used for dname compression. */ uint16_t compressed_dname_count; domain_type **compressed_dnames; /* * Indexed by domain->number, index 0 is reserved for the * query name when generated from a wildcard record. */ uint16_t *compressed_dname_offsets; size_t compressed_dname_offsets_size; /* number of temporary domains used for the query */ size_t number_temporary_domains; /* * Used for AXFR processing. */ int axfr_is_done; zone_type *axfr_zone; domain_type *axfr_current_domain; rrset_type *axfr_current_rrset; uint16_t axfr_current_rr; #ifdef RATELIMIT /* if we encountered a wildcard, its domain */ domain_type *wildcard_domain; #endif }; /* Check if the last write resulted in an overflow. */ static inline int query_overflow(struct query *q); /* * Store the offset of the specified domain in the dname compression * table. */ void query_put_dname_offset(struct query *query, domain_type *domain, uint16_t offset); /* * Lookup the offset of the specified domain in the dname compression * table. Offset 0 is used to indicate the domain is not yet in the * compression table. */ static inline uint16_t query_get_dname_offset(struct query *query, domain_type *domain) { return query->compressed_dname_offsets[domain->number]; } /* * Remove all compressed dnames that have an offset that points beyond * the end of the current answer. This must be done after some RRs * are truncated and before adding new RRs. Otherwise dnames may be * compressed using truncated data! */ void query_clear_dname_offsets(struct query *query, size_t max_offset); /* * Clear the compression tables. */ void query_clear_compression_tables(struct query *query); /* * Enter the specified domain into the compression table starting at * the specified offset. */ void query_add_compression_domain(struct query *query, domain_type *domain, uint16_t offset); /* * Create a new query structure. */ query_type *query_create(region_type *region, uint16_t *compressed_dname_offsets, size_t compressed_dname_size, domain_type **compressed_dnames); /* * Reset a query structure so it is ready for receiving and processing * a new query. */ void query_reset(query_type *query, size_t maxlen, int is_tcp); /* * Process a query and write the response in the query I/O buffer. */ query_state_type query_process(query_type *q, nsd_type *nsd); /* * Prepare the query structure for writing the response. The packet * data up-to the current packet limit is preserved. This usually * includes the packet header and question section. Space is reserved * for the optional EDNS record, if required. */ void query_prepare_response(query_type *q); /* * Add EDNS0 information to the response if required. */ void query_add_optional(query_type *q, nsd_type *nsd); /* * Write an error response into the query structure with the indicated * RCODE. */ query_state_type query_error(query_type *q, nsd_rc_type rcode); static inline int query_overflow(query_type *q) { return buffer_position(q->packet) > (q->maxlen - q->reserved_space); } #endif /* _QUERY_H_ */ nsd-4.1.26/nsd.h0000664000175000017500000002131613355344112012767 0ustar wouterwouter/* * nsd.h -- nsd(8) definitions and prototypes * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _NSD_H_ #define _NSD_H_ #include #include "dns.h" #include "edns.h" struct netio_handler; struct nsd_options; struct udb_base; struct daemon_remote; #ifdef USE_DNSTAP struct dt_collector; #endif /* The NSD runtime states and NSD ipc command values */ #define NSD_RUN 0 #define NSD_RELOAD 1 #define NSD_SHUTDOWN 2 #define NSD_STATS 3 #define NSD_REAP_CHILDREN 4 #define NSD_QUIT 5 /* * PASS_TO_XFRD is followed by the u16(len in network order) and * then network packet contents. packet is a notify(acl checked), or * xfr reply from a master(acl checked). * followed by u32(acl number that matched from notify/xfr acl). */ #define NSD_PASS_TO_XFRD 6 /* * RELOAD_REQ is sent when parent receives a SIGHUP and tells * xfrd that it wants to initiate a reload (and thus task swap). */ #define NSD_RELOAD_REQ 7 /* * RELOAD_DONE is sent at the end of a reload pass. * xfrd then knows that reload phase is over. */ #define NSD_RELOAD_DONE 8 /* * QUIT_SYNC is sent to signify a synchronisation of ipc * channel content during reload */ #define NSD_QUIT_SYNC 9 /* * QUIT_WITH_STATS is sent during a reload when BIND8_STATS is defined, * from parent to children. The stats are transferred too from child to * parent with this commandvalue, when the child is exiting. */ #define NSD_QUIT_WITH_STATS 10 /* * QUIT_CHILD is sent at exit, to make sure the child has exited so that * port53 is free when all of nsd's processes have exited at shutdown time */ #define NSD_QUIT_CHILD 11 #define NSD_SERVER_MAIN 0x0U #define NSD_SERVER_UDP 0x1U #define NSD_SERVER_TCP 0x2U #define NSD_SERVER_BOTH (NSD_SERVER_UDP | NSD_SERVER_TCP) #ifdef INET6 #define DEFAULT_AI_FAMILY AF_UNSPEC #else #define DEFAULT_AI_FAMILY AF_INET #endif #ifdef BIND8_STATS /* Counter for statistics */ typedef unsigned long stc_type; #define LASTELEM(arr) (sizeof(arr) / sizeof(arr[0]) - 1) #define STATUP(nsd, stc) nsd->st.stc++ /* #define STATUP2(nsd, stc, i) ((i) <= (LASTELEM(nsd->st.stc) - 1)) ? nsd->st.stc[(i)]++ : \ nsd->st.stc[LASTELEM(nsd->st.stc)]++ */ #define STATUP2(nsd, stc, i) nsd->st.stc[(i) <= (LASTELEM(nsd->st.stc) - 1) ? i : LASTELEM(nsd->st.stc)]++ #else /* BIND8_STATS */ #define STATUP(nsd, stc) /* Nothing */ #define STATUP2(nsd, stc, i) /* Nothing */ #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS /* increment zone statistic, checks if zone-nonNULL and zone array bounds */ #define ZTATUP(nsd, zone, stc) ( \ (zone && zone->zonestatid < nsd->zonestatsizenow) ? \ nsd->zonestatnow[zone->zonestatid].stc++ \ : 0) #define ZTATUP2(nsd, zone, stc, i) ( \ (zone && zone->zonestatid < nsd->zonestatsizenow) ? \ (nsd->zonestatnow[zone->zonestatid].stc[(i) <= (LASTELEM(nsd->zonestatnow[zone->zonestatid].stc) - 1) ? i : LASTELEM(nsd->zonestatnow[zone->zonestatid].stc)]++ ) \ : 0) #else /* USE_ZONE_STATS */ #define ZTATUP(nsd, zone, stc) /* Nothing */ #define ZTATUP2(nsd, zone, stc, i) /* Nothing */ #endif /* USE_ZONE_STATS */ struct nsd_socket { struct addrinfo * addr; int s; int fam; }; struct nsd_child { /* The type of child process (UDP or TCP handler). */ int kind; /* The child's process id. */ pid_t pid; /* child number in child array */ int child_num; /* * Socket used by the parent process to send commands and * receive responses to/from this child process. */ int child_fd; /* * Socket used by the child process to receive commands and * send responses from/to the parent process. */ int parent_fd; /* * IPC info, buffered for nonblocking writes to the child */ uint8_t need_to_send_STATS, need_to_send_QUIT; uint8_t need_to_exit, has_exited; /* * The handler for handling the commands from the child. */ struct netio_handler* handler; #ifdef BIND8_STATS stc_type query_count; #endif }; /* NSD configuration and run-time variables */ typedef struct nsd nsd_type; struct nsd { /* * Global region that is not deallocated until NSD shuts down. */ region_type *region; /* Run-time variables */ pid_t pid; volatile sig_atomic_t mode; volatile sig_atomic_t signal_hint_reload_hup; volatile sig_atomic_t signal_hint_reload; volatile sig_atomic_t signal_hint_child; volatile sig_atomic_t signal_hint_quit; volatile sig_atomic_t signal_hint_shutdown; volatile sig_atomic_t signal_hint_stats; volatile sig_atomic_t signal_hint_statsusr; volatile sig_atomic_t quit_sync_done; unsigned server_kind; struct namedb *db; int debug; size_t child_count; struct nsd_child *children; int restart_children; int reload_failed; /* NULL if this is the parent process. */ struct nsd_child *this_child; /* mmaps with data exchange from xfrd and reload */ struct udb_base* task[2]; int mytask; /* the base used by this (child)process */ struct event_base* event_base; /* the server_region used by this (child)process */ region_type* server_region; struct netio_handler* xfrd_listener; struct daemon_remote* rc; /* Configuration */ const char *dbfile; const char *pidfile; const char *log_filename; const char *username; uid_t uid; gid_t gid; const char *chrootdir; const char *version; const char *identity; uint16_t nsid_len; unsigned char *nsid; uint8_t file_rotation_ok; /* number of interfaces */ size_t ifs; uint8_t grab_ip6_optional; /* non0 if so_reuseport is in use, if so, tcp, udp array increased */ int reuseport; /* TCP specific configuration (array size ifs) */ struct nsd_socket* tcp; /* UDP specific configuration (array size ifs) */ struct nsd_socket* udp; edns_data_type edns_ipv4; #if defined(INET6) edns_data_type edns_ipv6; #endif int maximum_tcp_count; int current_tcp_count; int tcp_query_count; int tcp_timeout; int tcp_mss; int outgoing_tcp_mss; size_t ipv4_edns_size; size_t ipv6_edns_size; #ifdef BIND8_STATS struct nsdst { time_t boot; int period; /* Produce statistics dump every st_period seconds */ stc_type qtype[257]; /* Counters per qtype */ stc_type qclass[4]; /* Class IN or Class CH or other */ stc_type qudp, qudp6; /* Number of queries udp and udp6 */ stc_type ctcp, ctcp6; /* Number of tcp and tcp6 connections */ stc_type rcode[17], opcode[6]; /* Rcodes & opcodes */ /* Dropped, truncated, queries for nonconfigured zone, tx errors */ stc_type dropped, truncated, wrongzone, txerr, rxerr; stc_type edns, ednserr, raxfr, nona; uint64_t db_disk, db_mem; } st; /* per zone stats, each an array per zone-stat-idx, stats per zone is * add of [0][zoneidx] and [1][zoneidx]. */ struct nsdst* zonestat[2]; /* fd for zonestat mapping (otherwise mmaps cannot be shared between * processes and resized) */ int zonestatfd[2]; /* filenames */ char* zonestatfname[2]; /* size of the mmapped zone stat array (number of array entries) */ size_t zonestatsize[2], zonestatdesired, zonestatsizenow; /* current zonestat array to use */ struct nsdst* zonestatnow; #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* the dnstap collector process info */ struct dt_collector* dt_collector; /* the pipes from server processes to the dt_collector, * arrays of size child_count. Kept open for (re-)forks. */ int *dt_collector_fd_send, *dt_collector_fd_recv; #endif /* USE_DNSTAP */ /* ratelimit for errors, time value */ time_t err_limit_time; /* ratelimit for errors, packet count */ unsigned int err_limit_count; struct nsd_options* options; }; extern struct nsd nsd; /* nsd.c */ pid_t readpid(const char *file); int writepid(struct nsd *nsd); void unlinkpid(const char* file); void sig_handler(int sig); void bind8_stats(struct nsd *nsd); /* server.c */ int server_init(struct nsd *nsd); int server_prepare(struct nsd *nsd); void server_main(struct nsd *nsd); void server_child(struct nsd *nsd); void server_shutdown(struct nsd *nsd) ATTR_NORETURN; void server_close_all_sockets(struct nsd_socket sockets[], size_t n); struct event_base* nsd_child_event_base(void); /* extra domain numbers for temporary domains */ #define EXTRA_DOMAIN_NUMBERS 1024 #define SLOW_ACCEPT_TIMEOUT 2 /* in seconds */ /* ratelimit for error responses */ #define ERROR_RATELIMIT 100 /* qps */ /* allocate zonestat structures */ void server_zonestat_alloc(struct nsd* nsd); /* remap the mmaps for zonestat isx, to bytesize sz. Caller has to set * the zonestatsize */ void zonestat_remap(struct nsd* nsd, int idx, size_t sz); /* allocate and init xfrd variables */ void server_prepare_xfrd(struct nsd *nsd); /* start xfrdaemon (again) */ void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active); /* send SOA serial numbers to xfrd */ void server_send_soa_xfrd(struct nsd *nsd, int shortsoa); ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout); #endif /* _NSD_H_ */ nsd-4.1.26/lookup3.c0000664000175000017500000010704113135363374013601 0ustar wouterwouter/* February 2013(Wouter) patch defines for BSD endianness, from Brad Smith. January 2012(Wouter) added randomised initial value, fallout from 28c3. March 2007(Wouter) adapted from lookup3.c original, add config.h include. 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. */ /* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hashword(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. ------------------------------------------------------------------------------- */ /*#define SELF_TEST 1*/ #include "config.h" #include "lookup3.h" #include /* defines printf for tests */ #include /* defines time_t for timings in the test */ /*#include defines uint32_t etc (from config.h) */ #include /* attempt to define endianness */ #ifdef HAVE_SYS_TYPES_H # include /* attempt to define endianness (solaris) */ #endif #if defined(linux) || defined(__OpenBSD__) # ifdef HAVE_ENDIAN_H # include /* attempt to define endianness */ # else # include /* on older OpenBSD */ # endif #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include /* attempt to define endianness */ #endif /* random initial value */ static uint32_t raninit = 0xdeadbeef; void hash_set_raninit(uint32_t v) { raninit = v; } /* * My best guess at if you are big-endian or little-endian. This may * need adjustment. */ #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ __BYTE_ORDER == __LITTLE_ENDIAN) || \ (defined(i386) || defined(__i386__) || defined(__i486__) || \ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86)) # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 #elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ __BYTE_ORDER == __BIG_ENDIAN) || \ (defined(sparc) || defined(__sparc) || defined(__sparc__) || defined(POWERPC) || defined(mc68000) || defined(sel)) # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 #elif defined(_MACHINE_ENDIAN_H_) /* test for machine_endian_h protects failure if some are empty strings */ # if defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 # endif # if defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 # endif /* _MACHINE_ENDIAN_H_ */ #else # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 0 #endif #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) /* ------------------------------------------------------------------------------- mix -- mix 3 32-bit values reversibly. This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix(). If four pairs of (a,b,c) inputs are run through mix(), or through mix() in reverse, there are at least 32 bits of the output that are sometimes the same for one pair and different for another pair. This was tested for: * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this are 4 6 8 16 19 4 9 15 3 18 27 15 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) that fail to affect some output bits of (a,b,c), especially of a. The most thoroughly mixed value is c, but it doesn't really even achieve avalanche in c. This allows some parallelism. Read-after-writes are good at doubling the number of bits affected, so the goal of mixing pulls in the opposite direction as the goal of parallelism. I did what I could. Rotates seem to cost as much as shifts on every machine I could lay my hands on, and rotates are much kinder to the top and bottom bits, so I used rotates. ------------------------------------------------------------------------------- */ #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } /* ------------------------------------------------------------------------------- final -- final mixing of 3 32-bit values (a,b,c) into c Pairs of (a,b,c) values differing in only a few bits will usually produce values of c that look totally different. This was tested for * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: 14 11 25 16 4 14 24 12 14 25 16 4 14 24 and these came close: 4 8 15 26 3 22 24 10 8 15 26 3 22 24 11 8 15 26 3 22 24 ------------------------------------------------------------------------------- */ #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c,4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } /* -------------------------------------------------------------------- This works on all machines. To be useful, it requires -- that the key be an array of uint32_t's, and -- that the length be the number of uint32_t's in the key The function hashword() is identical to hashlittle() on little-endian machines, and identical to hashbig() on big-endian machines, except that the length has to be measured in uint32_ts rather than in bytes. hashlittle() is more complicated than hashword() only because hashlittle() has to dance around fitting the key bytes into registers. -------------------------------------------------------------------- */ uint32_t hashword( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t initval) /* the previous hash, or an arbitrary value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = raninit + (((uint32_t)length)<<2) + initval; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ 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 */ break; } /*------------------------------------------------------ report the result */ return c; } #ifdef SELF_TEST /* -------------------------------------------------------------------- hashword2() -- same as hashword(), but take two seeds and return two 32-bit values. pc and pb must both be nonnull, and *pc and *pb must both be initialized with seeds. If you pass in (*pb)==0, the output (*pc) will be the same as the return value from hashword(). -------------------------------------------------------------------- */ void hashword2 ( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t *pc, /* IN: seed OUT: primary hash value */ uint32_t *pb) /* IN: more seed OUT: secondary hash value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = raninit + ((uint32_t)(length<<2)) + *pc; c += *pb; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ *pc=c; *pb=b; } #endif /* SELF_TEST */ /* ------------------------------------------------------------------------------- hashlittle() -- hash a variable-length key into a 32-bit value k : the key (the unaligned variable-length array of bytes) length : the length of the key, counting by bytes initval : can be any 4-byte value Returns a 32-bit value. Every bit of the key affects every bit of the return value. Two keys differing by one or two bits will have totally different hash values. The best hash table sizes are powers of 2. There is no need to do mod a prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. For example, if you need only 10 bits, do h = (h & hashmask(10)); In which case, the hash table should have hashsize(10) elements. If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0; i 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return c; } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return c; /* zero length requires no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ 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; } } final(a,b,c); return c; } #ifdef SELF_TEST /* * hashlittle2: return 2 32-bit hash values * * This is identical to hashlittle(), except it returns two 32-bit hash * values instead of just one. This is good enough for hash table * lookup with 2^^64 buckets, or if you want a second hash if you're not * happy with the first, or if you want a probably-unique 64-bit ID for * the key. *pc is better mixed than *pb, so use *pc first. If you want * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". */ void hashlittle2( const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ { uint32_t a,b,c; /* internal state */ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ /* Set up the internal state */ a = b = c = raninit + ((uint32_t)length) + *pc; c += *pb; u.ptr = key; if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ #ifdef VALGRIND const uint8_t *k8; #endif /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; case 11: c+=((uint32_t)k[10])<<16; case 10: c+=((uint32_t)k[9])<<8; case 9 : c+=k[8]; case 8 : b+=((uint32_t)k[7])<<24; case 7 : b+=((uint32_t)k[6])<<16; case 6 : b+=((uint32_t)k[5])<<8; case 5 : b+=k[4]; case 4 : a+=((uint32_t)k[3])<<24; case 3 : a+=((uint32_t)k[2])<<16; case 2 : a+=((uint32_t)k[1])<<8; case 1 : a+=k[0]; break; case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ } } final(a,b,c); *pc=c; *pb=b; } #endif /* SELF_TEST */ #if 0 /* currently not used */ /* * hashbig(): * This is the same as hashword() on big-endian machines. It is different * from hashlittle() on all machines. hashbig() takes advantage of * big-endian byte ordering. */ uint32_t hashbig( const void *key, size_t length, uint32_t initval) { uint32_t a,b,c; union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ /* Set up the internal state */ a = b = c = raninit + ((uint32_t)length) + initval; u.ptr = key; if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ #ifdef VALGRIND const uint8_t *k8; #endif /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]<<8" actually reads beyond the end of the string, but * then shifts out the part it's not allowed to read. Because the * string is aligned, the illegal read is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticeably faster for short strings (like English words). */ #ifndef VALGRIND switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; case 5 : b+=k[1]&0xff000000; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff00; break; case 2 : a+=k[0]&0xffff0000; break; case 1 : a+=k[0]&0xff000000; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) /* all the case statements fall through */ { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ case 1 : a+=((uint32_t)k8[0])<<24; break; case 0 : return c; } #endif /* !VALGRIND */ } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += ((uint32_t)k[0])<<24; a += ((uint32_t)k[1])<<16; a += ((uint32_t)k[2])<<8; a += ((uint32_t)k[3]); b += ((uint32_t)k[4])<<24; b += ((uint32_t)k[5])<<16; b += ((uint32_t)k[6])<<8; b += ((uint32_t)k[7]); c += ((uint32_t)k[8])<<24; c += ((uint32_t)k[9])<<16; c += ((uint32_t)k[10])<<8; c += ((uint32_t)k[11]); mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=k[11]; case 11: c+=((uint32_t)k[10])<<8; case 10: c+=((uint32_t)k[9])<<16; case 9 : c+=((uint32_t)k[8])<<24; case 8 : b+=k[7]; case 7 : b+=((uint32_t)k[6])<<8; case 6 : b+=((uint32_t)k[5])<<16; case 5 : b+=((uint32_t)k[4])<<24; case 4 : a+=k[3]; case 3 : a+=((uint32_t)k[2])<<8; case 2 : a+=((uint32_t)k[1])<<16; case 1 : a+=((uint32_t)k[0])<<24; break; case 0 : return c; } } final(a,b,c); return c; } #endif /* 0 == currently not used */ #ifdef SELF_TEST /* used for timings */ void driver1() { uint8_t buf[256]; uint32_t i; uint32_t h=0; time_t a,z; time(&a); for (i=0; i<256; ++i) buf[i] = 'x'; for (i=0; i<1; ++i) { h = hashlittle(&buf[0],1,h); } time(&z); if (z-a > 0) printf("time %lld %.8x\n", (long long) z-a, h); } /* check that every input bit changes every output bit half the time */ #define HASHSTATE 1 #define HASHLEN 1 #define MAXPAIR 60 #define MAXLEN 70 void driver2() { uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; uint32_t x[HASHSTATE],y[HASHSTATE]; uint32_t hlen; printf("No more than %d trials should ever be needed \n",MAXPAIR/2); for (hlen=0; hlen < MAXLEN; ++hlen) { z=0; for (i=0; i>(8-j)); c[0] = hashlittle(a, hlen, m); b[i] ^= ((k+1)<>(8-j)); d[0] = hashlittle(b, hlen, m); /* check every bit is 1, 0, set, and not set at least once */ for (l=0; lz) z=k; if (k==MAXPAIR) { printf("Some bit didn't change: "); printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0],f[0],g[0],h[0],x[0],y[0]); printf("i %d j %d m %d len %d\n", i, j, m, hlen); } if (z==MAXPAIR) goto done; } } } done: if (z < MAXPAIR) { printf("Mix success %2d bytes %2d initvals ",i,m); printf("required %d trials\n", z/2); } } printf("\n"); } /* Check for reading beyond the end of the buffer and alignment problems */ void driver3() { uint8_t buf[MAXLEN+20], *b; uint32_t len; uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; uint32_t h; uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; uint32_t i; uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; uint32_t j; uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; uint32_t ref,x,y; uint8_t *p; printf("Endianness. These lines should all be the same (for values filled in):\n"); printf("%.8x %.8x %.8x\n", hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); p = q; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qq[1]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqq[2]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqqq[3]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); printf("\n"); /* check that hashlittle2 and hashlittle produce the same results */ i=47; j=0; hashlittle2(q, sizeof(q), &i, &j); if (hashlittle(q, sizeof(q), 47) != i) printf("hashlittle2 and hashlittle mismatch\n"); /* check that hashword2 and hashword produce the same results */ len = raninit; i=47, j=0; hashword2(&len, 1, &i, &j); if (hashword(&len, 1, 47) != i) printf("hashword2 and hashword mismatch %x %x\n", i, hashword(&len, 1, 47)); /* check hashlittle doesn't read before or after the ends of the string */ for (h=0, b=buf+1; h<8; ++h, ++b) { for (i=0; i header file. */ #undef HAVE_ARPA_INET_H /* Whether the C compiler accepts the "format" attribute */ #undef HAVE_ATTR_FORMAT /* Whether the C compiler accepts the "noreturn" attribute */ #undef HAVE_ATTR_NORETURN /* Whether the C compiler accepts the "unused" attribute */ #undef HAVE_ATTR_UNUSED /* Define to 1 if you have the `b64_ntop' function. */ #undef HAVE_B64_NTOP /* Define to 1 if you have the `b64_pton' function. */ #undef HAVE_B64_PTON /* Define to 1 if you have the `basename' function. */ #undef HAVE_BASENAME /* Define to 1 if your system has a working `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the `chroot' function. */ #undef HAVE_CHROOT /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* if time.h provides ctime_r prototype */ #undef HAVE_CTIME_R_PROTO /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT /* Define to 1 if you have the `ERR_load_crypto_strings' function. */ #undef HAVE_ERR_LOAD_CRYPTO_STRINGS /* Define to 1 if you have the `event_base_free' function. */ #undef HAVE_EVENT_BASE_FREE /* Define to 1 if you have the `event_base_get_method' function. */ #undef HAVE_EVENT_BASE_GET_METHOD /* Define to 1 if you have the `event_base_new' function. */ #undef HAVE_EVENT_BASE_NEW /* Define to 1 if you have the `event_base_once' function. */ #undef HAVE_EVENT_BASE_ONCE /* Define to 1 if you have the header file. */ #undef HAVE_EVENT_H /* Define to 1 if you have the `EVP_cleanup' function. */ #undef HAVE_EVP_CLEANUP /* Define to 1 if you have the `ev_default_loop' function. */ #undef HAVE_EV_DEFAULT_LOOP /* Define to 1 if you have the `ev_loop' function. */ #undef HAVE_EV_LOOP /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `freeaddrinfo' function. */ #undef HAVE_FREEADDRINFO /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO /* Define to 1 if you have the `gai_strerror' function. */ #undef HAVE_GAI_STRERROR /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `gethostname' function. */ #undef HAVE_GETHOSTNAME /* Define to 1 if you have the `getnameinfo' function. */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the `getpwnam' function. */ #undef HAVE_GETPWNAM /* Define to 1 if you have the `glob' function. */ #undef HAVE_GLOB /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the `HMAC_CTX_new' function. */ #undef HAVE_HMAC_CTX_NEW /* Define to 1 if you have the `HMAC_CTX_reset' function. */ #undef HAVE_HMAC_CTX_RESET /* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON /* Define to 1 if you have the `initgroups' function. */ #undef HAVE_INITGROUPS /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `crypto' library (-lcrypto). */ #undef HAVE_LIBCRYPTO /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* Define to 1 if you have the `munmap' function. */ #undef HAVE_MUNMAP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define to 1 if you have the `OPENSSL_init_crypto' function. */ #undef HAVE_OPENSSL_INIT_CRYPTO /* Define to 1 if you have the `OPENSSL_init_ssl' function. */ #undef HAVE_OPENSSL_INIT_SSL /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_RAND_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the `ppoll' function. */ #undef HAVE_PPOLL /* Define to 1 if you have the `pselect' function. */ #undef HAVE_PSELECT /* if sys/select.h provides pselect prototype */ #undef HAVE_PSELECT_PROTO /* Define to 1 if you have the `pwrite' function. */ #undef HAVE_PWRITE /* Define to 1 if you have the `reallocarray' function. */ #undef HAVE_REALLOCARRAY /* Define if recvmmsg is implemented */ #undef HAVE_RECVMMSG /* Define if sendmmsg is implemented */ #undef HAVE_SENDMMSG /* Define to 1 if you have the `setregid' function. */ #undef HAVE_SETREGID /* Define to 1 if you have the `setresgid' function. */ #undef HAVE_SETRESGID /* Define to 1 if you have the `setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the `setreuid' function. */ #undef HAVE_SETREUID /* Define to 1 if you have the `setusercontext' function. */ #undef HAVE_SETUSERCONTEXT /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `sigprocmask' function. */ #undef HAVE_SIGPROCMASK /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define if you have the SSL libraries installed. */ #undef HAVE_SSL /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strptime' function. */ #undef HAVE_STRPTIME /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ #undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIMENSEC /* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC /* If time.h has a struct timespec (for pselect). */ #undef HAVE_STRUCT_TIMESPEC /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BITYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the `tzset' function. */ #undef HAVE_TZSET /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define this if you have double va_list definitions. */ #undef HAVE_VA_LIST_DOUBLE_DEF /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if you have the `writev' function. */ #undef HAVE_WRITEV /* Define to the default nsd identity. */ #undef IDENTITY /* Define this to enable IPv6 support. */ #undef INET6 /* If flex defines yy_current_buffer as a macro */ #undef LEX_DEFINES_YY_CURRENT_BUFFER /* Define to the maximum message length to pass to syslog. */ #undef MAXSYSLOGMSGLEN /* Define this to cleanup memory at exit (eg. for valgrind, etc.) */ #undef MEMCLEAN /* Define if memcmp() does not compare unsigned bytes */ #undef MEMCMP_IS_BROKEN /* Define this to enable response minimalization to reduce truncation. */ #undef MINIMAL_RESPONSES /* Define if mkdir has one argument. */ #undef MKDIR_HAS_ONE_ARG /* Undefine this to enable internal runtime checks. */ #undef NDEBUG /* Define if the network stack does not fully support nonblocking io (causes lower performance). */ #undef NONBLOCKING_IS_BROKEN /* Define to the default nsd-control port. */ #undef NSD_CONTROL_PORT /* Define to nsd-control proto version. */ #undef NSD_CONTROL_VERSION /* Pathname to start nsd from nsd-control */ #undef NSD_START_PATH /* Define this to enable NSEC3 support. */ #undef NSEC3 /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define this to use packed structure alignment. */ #undef PACKED_STRUCTS /* Pathname to the NSD pidfile */ #undef PIDFILE /* Define this to enable rate limiting. */ #undef RATELIMIT /* Define this to set ratelimit to off by default. */ #undef RATELIMIT_DEFAULT_OFF /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define this to configure as a root server. */ #undef ROOT_SERVER /* The size of `off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T /* The size of `void*', as computed by sizeof. */ #undef SIZEOF_VOIDP /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* strptime is available from time.h with some defines. */ #undef STRPTIME_NEEDS_DEFINES /* use default strptime. */ #undef STRPTIME_WORKS /* Define to the backlog to be used with listen. */ #undef TCP_BACKLOG /* Define to the default maximum message length. */ #undef TCP_MAX_MESSAGE_LEN /* Define to the default tcp port. */ #undef TCP_PORT /* Define to the default tcp timeout. */ #undef TCP_TIMEOUT /* Define to the default maximum udp message length. */ #undef UDP_MAX_MESSAGE_LEN /* Define to the default udp port. */ #undef UDP_PORT /* the user name to drop privileges to */ #undef USER /* Define to 1 to enable dnstap support */ #undef USE_DNSTAP /* Define if you want to use internal select based events */ #undef USE_MINI_EVENT /* Define this to enable mmap instead of malloc. Experimental. */ #undef USE_MMAP_ALLOC /* Define this to configure to use the radix tree. */ #undef USE_RADIX_TREE /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Define this to enable per-zone statistics gathering. */ #undef USE_ZONE_STATS /* Define to the NSD version to answer version.server query. */ #undef VERSION /* Pathname to the NSD xfrd zone timer state file. */ #undef XFRDFILE /* Pathname to where the NSD transfer dir is created. */ #undef XFRDIR /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Pathname to the NSD zone list file. */ #undef ZONELISTFILE /* NSD default location for zone files. Empty string or NULL to disable. */ #undef ZONESDIR /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to 1 if on MINIX. */ #undef _MINIX /* Enable for compile on Minix */ #undef _NETBSD_SOURCE /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if doesn't define. */ #undef gid_t /* in_addr_t */ #undef in_addr_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define "int16_t" to "short" if "int16_t" is missing */ #undef int16_t /* Define "int32_t" to "int" if "int32_t" is missing */ #undef int32_t /* Define "int64_t" to "long long" if "int64_t" is missing */ #undef int64_t /* Define "int8_t" to "char" if "int8_t" is missing */ #undef int8_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef pid_t /* Define "sig_atomic_t" to "int" if "sig_atomic_t" is missing */ #undef sig_atomic_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define "socklen_t" to "int" if "socklen_t" is missing */ #undef socklen_t /* Fallback member name for socket family in struct sockaddr_storage */ #undef ss_family /* Define "ssize_t" to "int" if "ssize_t" is missing */ #undef ssize_t /* Define "suseconds_t" to "time_t" if "suseconds_t" is missing */ #undef suseconds_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define "uint16_t" to "unsigned short" if "uint16_t" is missing */ #undef uint16_t /* Define "uint32_t" to "unsigned int" if "uint32_t" is missing */ #undef uint32_t /* Define "uint64_t" to "unsigned long long" if "uint64_t" is missing */ #undef uint64_t /* Define "uint8_t" to "unsigned char" if "uint8_t" is missing */ #undef uint8_t /* Define "uintptr_t" to "void*" if "uintptr_t" is missing */ #undef uintptr_t /* Define as `fork' if `vfork' does not work. */ #undef vfork /* define before includes as it specifies what standard to use. */ #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \ || !defined (HAVE_CTIME_R_PROTO) \ || defined (STRPTIME_NEEDS_DEFINES) # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 # endif # ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 200112 # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE 1 # endif # ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 # endif # ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 # endif # ifndef _STDC_C99 # define _STDC_C99 1 # endif # ifndef _ALL_SOURCE # define _ALL_SOURCE 1 # endif #endif #ifdef HAVE_VA_LIST_DOUBLE_DEF /* workaround double va_list definition on some platforms */ # ifndef _VA_LIST_DEFINED # define _VA_LIST_DEFINED # endif #endif #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif #ifdef HAVE_ATTR_FORMAT #define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ #define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ #if defined(__cplusplus) #define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) #define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ #define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ #ifndef AF_INET6 #define AF_INET6 28 #endif /* AF_INET6 */ /* maximum nesting of included files */ #define MAXINCLUDES 10 #ifndef HAVE_B64_NTOP int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); #endif /* !HAVE_B64_NTOP */ #ifndef HAVE_B64_PTON int b64_pton(char const *src, uint8_t *target, size_t targsize); #endif /* !HAVE_B64_PTON */ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ #ifndef HAVE_SNPRINTF #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ #ifndef HAVE_INET_PTON int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_REALLOCARRAY void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif #ifndef HAVE_STRPTIME #define HAVE_STRPTIME 1 char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif #ifdef MEMCMP_IS_BROKEN #include "compat/memcmp.h" #define memcmp memcmp_nsd int memcmp(const void *x, const void *y, size_t n); #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif /* provide timespec def if not available */ #ifndef CONFIG_DEFINES #define CONFIG_DEFINES #ifndef HAVE_STRUCT_TIMESPEC #ifndef __timespec_defined #define __timespec_defined 1 struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* !__timespec_defined */ #endif /* !HAVE_STRUCT_TIMESPEC */ #endif /* !CONFIG_DEFINES */ #ifdef PACKED_STRUCTS #define ATTR_PACKED __attribute__((packed)) #else #define ATTR_PACKED #endif nsd-4.1.26/edns.c0000664000175000017500000000774212764236564013154 0ustar wouterwouter/* * edns.c -- EDNS definitions (RFC 2671). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include "dns.h" #include "edns.h" #include "nsd.h" #include "query.h" void edns_init_data(edns_data_type *data, uint16_t max_length) { memset(data, 0, sizeof(edns_data_type)); /* record type: OPT */ data->ok[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ data->ok[2] = TYPE_OPT & 0x00ff; /* type_lo */ /* udp payload size */ data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */ data->ok[4] = max_length & 0x00ff; /* size_lo */ data->error[1] = (TYPE_OPT & 0xff00) >> 8; /* type_hi */ data->error[2] = TYPE_OPT & 0x00ff; /* type_lo */ data->error[3] = (max_length & 0xff00) >> 8; /* size_hi */ data->error[4] = max_length & 0x00ff; /* size_lo */ data->error[5] = 1; /* XXX Extended RCODE=BAD VERS */ } void edns_init_nsid(edns_data_type *data, uint16_t nsid_len) { /* add nsid length bytes */ data->rdata_nsid[0] = ((OPT_HDR + nsid_len) & 0xff00) >> 8; /* length_hi */ data->rdata_nsid[1] = ((OPT_HDR + nsid_len) & 0x00ff); /* length_lo */ /* NSID OPT HDR */ data->nsid[0] = (NSID_CODE & 0xff00) >> 8; data->nsid[1] = (NSID_CODE & 0x00ff); data->nsid[2] = (nsid_len & 0xff00) >> 8; data->nsid[3] = (nsid_len & 0x00ff); } void edns_init_record(edns_record_type *edns) { edns->status = EDNS_NOT_PRESENT; edns->position = 0; edns->maxlen = 0; edns->opt_reserved_space = 0; edns->dnssec_ok = 0; edns->nsid = 0; } /** handle a single edns option in the query */ static int edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, edns_record_type* edns, struct query* query, nsd_type* nsd) { (void) query; /* in case edns options need the query structure */ /* handle opt code and read the optlen bytes from the packet */ switch(optcode) { case NSID_CODE: /* is NSID enabled? */ if(nsd->nsid_len > 0) { edns->nsid = 1; /* we have to check optlen, and move the buffer along */ buffer_skip(packet, optlen); /* in the reply we need space for optcode+optlen+nsid_bytes */ edns->opt_reserved_space += OPT_HDR + nsd->nsid_len; } else { /* ignore option */ buffer_skip(packet, optlen); } break; default: buffer_skip(packet, optlen); break; } return 1; } int edns_parse_record(edns_record_type *edns, buffer_type *packet, query_type* query, nsd_type* nsd) { /* OPT record type... */ uint8_t opt_owner; uint16_t opt_type; uint16_t opt_class; uint8_t opt_version; uint16_t opt_flags; uint16_t opt_rdlen; edns->position = buffer_position(packet); if (!buffer_available(packet, (OPT_LEN + OPT_RDATA))) return 0; opt_owner = buffer_read_u8(packet); opt_type = buffer_read_u16(packet); if (opt_owner != 0 || opt_type != TYPE_OPT) { /* Not EDNS. */ buffer_set_position(packet, edns->position); return 0; } opt_class = buffer_read_u16(packet); (void)buffer_read_u8(packet); /* opt_extended_rcode */ opt_version = buffer_read_u8(packet); opt_flags = buffer_read_u16(packet); opt_rdlen = buffer_read_u16(packet); if (opt_version != 0) { /* The only error is VERSION not implemented */ edns->status = EDNS_ERROR; return 1; } if (opt_rdlen > 0) { if(!buffer_available(packet, opt_rdlen)) return 0; /* there is more to come, read opt code */ while(opt_rdlen >= 4) { uint16_t optcode = buffer_read_u16(packet); uint16_t optlen = buffer_read_u16(packet); if(opt_rdlen < 4+optlen) return 0; /* opt too long, formerr */ opt_rdlen -= (4+optlen); if(!edns_handle_option(optcode, optlen, packet, edns, query, nsd)) return 0; } if(opt_rdlen != 0) return 0; } edns->status = EDNS_OK; edns->maxlen = opt_class; edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK; return 1; } size_t edns_reserved_space(edns_record_type *edns) { /* MIEK; when a pkt is too large?? */ return edns->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space); } nsd-4.1.26/server.c0000664000175000017500000026023613374754276013533 0ustar wouterwouter/* * server.c -- nsd(8) network input/output * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SHUT_WR #define SHUT_WR 1 #endif #ifdef HAVE_MMAP #include #endif /* HAVE_MMAP */ #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "axfr.h" #include "namedb.h" #include "netio.h" #include "xfrd.h" #include "xfrd-tcp.h" #include "xfrd-disk.h" #include "difffile.h" #include "nsec3.h" #include "ipc.h" #include "udb.h" #include "remote.h" #include "lookup3.h" #include "rrl.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif #define RELOAD_SYNC_TIMEOUT 25 /* seconds */ /* * Data for the UDP handlers. */ struct udp_handler_data { struct nsd *nsd; struct nsd_socket *socket; query_type *query; }; struct tcp_accept_handler_data { struct nsd *nsd; struct nsd_socket *socket; int event_added; struct event event; }; /* * These globals are used to enable the TCP accept handlers * when the number of TCP connection drops below the maximum * number of TCP connections. */ static size_t tcp_accept_handler_count; static struct tcp_accept_handler_data* tcp_accept_handlers; static struct event slowaccept_event; static int slowaccept; #ifndef NONBLOCKING_IS_BROKEN # define NUM_RECV_PER_SELECT 100 #endif #if (!defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG)) struct mmsghdr msgs[NUM_RECV_PER_SELECT]; struct iovec iovecs[NUM_RECV_PER_SELECT]; struct query *queries[NUM_RECV_PER_SELECT]; #endif /* * Data for the TCP connection handlers. * * The TCP handlers use non-blocking I/O. This is necessary to avoid * blocking the entire server on a slow TCP connection, but does make * reading from and writing to the socket more complicated. * * Basically, whenever a read/write would block (indicated by the * EAGAIN errno variable) we remember the position we were reading * from/writing to and return from the TCP reading/writing event * handler. When the socket becomes readable/writable again we * continue from the same position. */ struct tcp_handler_data { /* * The region used to allocate all TCP connection related * data, including this structure. This region is destroyed * when the connection is closed. */ region_type* region; /* * The global nsd structure. */ struct nsd* nsd; /* * The current query data for this TCP connection. */ query_type* query; /* * The query_state is used to remember if we are performing an * AXFR, if we're done processing, or if we should discard the * query and connection. */ query_state_type query_state; /* * The event for the file descriptor and tcp timeout */ struct event event; /* * The bytes_transmitted field is used to remember the number * of bytes transmitted when receiving or sending a DNS * packet. The count includes the two additional bytes used * to specify the packet length on a TCP connection. */ size_t bytes_transmitted; /* * The number of queries handled by this specific TCP connection. */ int query_count; /* * The timeout in msec for this tcp connection */ int tcp_timeout; }; /* * Handle incoming queries on the UDP server sockets. */ static void handle_udp(int fd, short event, void* arg); /* * Handle incoming connections on the TCP sockets. These handlers * usually wait for the NETIO_EVENT_READ event (indicating an incoming * connection) but are disabled when the number of current TCP * connections is equal to the maximum number of TCP connections. * Disabling is done by changing the handler to wait for the * NETIO_EVENT_NONE type. This is done using the function * configure_tcp_accept_handlers. */ static void handle_tcp_accept(int fd, short event, void* arg); /* * Handle incoming queries on a TCP connection. The TCP connections * are configured to be non-blocking and the handler may be called * multiple times before a complete query is received. */ static void handle_tcp_reading(int fd, short event, void* arg); /* * Handle outgoing responses on a TCP connection. The TCP connections * are configured to be non-blocking and the handler may be called * multiple times before a complete response is sent. */ static void handle_tcp_writing(int fd, short event, void* arg); /* * Send all children the quit nonblocking, then close pipe. */ static void send_children_quit(struct nsd* nsd); /* same, for shutdown time, waits for child to exit to avoid restart issues */ static void send_children_quit_and_wait(struct nsd* nsd); /* set childrens flags to send NSD_STATS to them */ #ifdef BIND8_STATS static void set_children_stats(struct nsd* nsd); #endif /* BIND8_STATS */ /* * Change the event types the HANDLERS are interested in to EVENT_TYPES. */ static void configure_handler_event_types(short event_types); static uint16_t *compressed_dname_offsets = 0; static uint32_t compression_table_capacity = 0; static uint32_t compression_table_size = 0; static domain_type* compressed_dnames[MAXRRSPP]; /* * Remove the specified pid from the list of child pids. Returns -1 if * the pid is not in the list, child_num otherwise. The field is set to 0. */ static int delete_child_pid(struct nsd *nsd, pid_t pid) { size_t i; for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid == pid) { nsd->children[i].pid = 0; if(!nsd->children[i].need_to_exit) { if(nsd->children[i].child_fd != -1) close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; if(nsd->children[i].handler) nsd->children[i].handler->fd = -1; } return i; } } return -1; } /* * Restart child servers if necessary. */ static int restart_child_servers(struct nsd *nsd, region_type* region, netio_type* netio, int* xfrd_sock_p) { struct main_ipc_handler_data *ipc_data; size_t i; int sv[2]; /* Fork the child processes... */ for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid <= 0) { if (nsd->children[i].child_fd != -1) close(nsd->children[i].child_fd); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { log_msg(LOG_ERR, "socketpair: %s", strerror(errno)); return -1; } nsd->children[i].child_fd = sv[0]; nsd->children[i].parent_fd = sv[1]; nsd->children[i].pid = fork(); switch (nsd->children[i].pid) { default: /* SERVER MAIN */ close(nsd->children[i].parent_fd); nsd->children[i].parent_fd = -1; if (fcntl(nsd->children[i].child_fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } if(!nsd->children[i].handler) { ipc_data = (struct main_ipc_handler_data*) region_alloc( region, sizeof(struct main_ipc_handler_data)); ipc_data->nsd = nsd; ipc_data->child = &nsd->children[i]; ipc_data->child_num = i; ipc_data->xfrd_sock = xfrd_sock_p; ipc_data->packet = buffer_create(region, QIOBUFSZ); ipc_data->forward_mode = 0; ipc_data->got_bytes = 0; ipc_data->total_bytes = 0; ipc_data->acl_num = 0; nsd->children[i].handler = (struct netio_handler*) region_alloc( region, sizeof(struct netio_handler)); nsd->children[i].handler->fd = nsd->children[i].child_fd; nsd->children[i].handler->timeout = NULL; nsd->children[i].handler->user_data = ipc_data; nsd->children[i].handler->event_types = NETIO_EVENT_READ; nsd->children[i].handler->event_handler = parent_handle_child_command; netio_add_handler(netio, nsd->children[i].handler); } /* clear any ongoing ipc */ ipc_data = (struct main_ipc_handler_data*) nsd->children[i].handler->user_data; ipc_data->forward_mode = 0; /* restart - update fd */ nsd->children[i].handler->fd = nsd->children[i].child_fd; break; case 0: /* CHILD */ /* the child need not be able to access the * nsd.db file */ namedb_close_udb(nsd->db); #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(region); #endif nsd->pid = 0; nsd->child_count = 0; nsd->server_kind = nsd->children[i].kind; nsd->this_child = &nsd->children[i]; nsd->this_child->child_num = i; /* remove signal flags inherited from parent the parent will handle them. */ nsd->signal_hint_reload_hup = 0; nsd->signal_hint_reload = 0; nsd->signal_hint_child = 0; nsd->signal_hint_quit = 0; nsd->signal_hint_shutdown = 0; nsd->signal_hint_stats = 0; nsd->signal_hint_statsusr = 0; close(*xfrd_sock_p); close(nsd->this_child->child_fd); nsd->this_child->child_fd = -1; if (fcntl(nsd->this_child->parent_fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } server_child(nsd); /* NOTREACH */ exit(0); case -1: log_msg(LOG_ERR, "fork failed: %s", strerror(errno)); return -1; } } } return 0; } #ifdef BIND8_STATS static void set_bind8_alarm(struct nsd* nsd) { /* resync so that the next alarm is on the next whole minute */ if(nsd->st.period > 0) /* % by 0 gives divbyzero error */ alarm(nsd->st.period - (time(NULL) % nsd->st.period)); } #endif /* set zone stat ids for zones initially read in */ static void zonestatid_tree_set(struct nsd* nsd) { struct radnode* n; for(n=radix_first(nsd->db->zonetree); n; n=radix_next(n)) { zone_type* zone = (zone_type*)n->elem; zone->zonestatid = getzonestatid(nsd->options, zone->opts); } } #ifdef USE_ZONE_STATS void server_zonestat_alloc(struct nsd* nsd) { size_t num = (nsd->options->zonestatnames->count==0?1: nsd->options->zonestatnames->count); size_t sz = sizeof(struct nsdst)*num; char tmpfile[256]; uint8_t z = 0; /* file names */ nsd->zonestatfname[0] = 0; nsd->zonestatfname[1] = 0; snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.0", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[0] = region_strdup(nsd->region, tmpfile); snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.1", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[1] = region_strdup(nsd->region, tmpfile); /* file descriptors */ nsd->zonestatfd[0] = open(nsd->zonestatfname[0], O_CREAT|O_RDWR, 0600); if(nsd->zonestatfd[0] == -1) { log_msg(LOG_ERR, "cannot create %s: %s", nsd->zonestatfname[0], strerror(errno)); exit(1); } nsd->zonestatfd[1] = open(nsd->zonestatfname[1], O_CREAT|O_RDWR, 0600); if(nsd->zonestatfd[0] == -1) { log_msg(LOG_ERR, "cannot create %s: %s", nsd->zonestatfname[1], strerror(errno)); close(nsd->zonestatfd[0]); unlink(nsd->zonestatfname[0]); exit(1); } #ifdef HAVE_MMAP if(lseek(nsd->zonestatfd[0], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[0], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[0], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[0], strerror(errno)); exit(1); } if(lseek(nsd->zonestatfd[1], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[1], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[1], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[1], strerror(errno)); exit(1); } nsd->zonestat[0] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[0], 0); if(nsd->zonestat[0] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } nsd->zonestat[1] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[1], 0); if(nsd->zonestat[1] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); exit(1); } memset(nsd->zonestat[0], 0, sz); memset(nsd->zonestat[1], 0, sz); nsd->zonestatsize[0] = num; nsd->zonestatsize[1] = num; nsd->zonestatdesired = num; nsd->zonestatsizenow = num; nsd->zonestatnow = nsd->zonestat[0]; #endif /* HAVE_MMAP */ } void zonestat_remap(struct nsd* nsd, int idx, size_t sz) { #ifdef HAVE_MMAP #ifdef MREMAP_MAYMOVE nsd->zonestat[idx] = (struct nsdst*)mremap(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx], sz, MREMAP_MAYMOVE); if(nsd->zonestat[idx] == MAP_FAILED) { log_msg(LOG_ERR, "mremap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE MREMAP */ if(msync(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx], MS_ASYNC) != 0) log_msg(LOG_ERR, "msync failed: %s", strerror(errno)); if(munmap(nsd->zonestat[idx], sizeof(struct nsdst)*nsd->zonestatsize[idx]) != 0) log_msg(LOG_ERR, "munmap failed: %s", strerror(errno)); nsd->zonestat[idx] = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, nsd->zonestatfd[idx], 0); if(nsd->zonestat[idx] == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); exit(1); } #endif /* MREMAP */ #endif /* HAVE_MMAP */ } /* realloc the zonestat array for the one that is not currently in use, * to match the desired new size of the array (if applicable) */ void server_zonestat_realloc(struct nsd* nsd) { #ifdef HAVE_MMAP uint8_t z = 0; size_t sz; int idx = 0; /* index of the zonestat array that is not in use */ if(nsd->zonestatnow == nsd->zonestat[0]) idx = 1; if(nsd->zonestatsize[idx] == nsd->zonestatdesired) return; sz = sizeof(struct nsdst)*nsd->zonestatdesired; if(lseek(nsd->zonestatfd[idx], (off_t)sz-1, SEEK_SET) == -1) { log_msg(LOG_ERR, "lseek %s: %s", nsd->zonestatfname[idx], strerror(errno)); exit(1); } if(write(nsd->zonestatfd[idx], &z, 1) == -1) { log_msg(LOG_ERR, "cannot extend stat file %s (%s)", nsd->zonestatfname[idx], strerror(errno)); exit(1); } zonestat_remap(nsd, idx, sz); /* zero the newly allocated region */ if(nsd->zonestatdesired > nsd->zonestatsize[idx]) { memset(((char*)nsd->zonestat[idx])+sizeof(struct nsdst) * nsd->zonestatsize[idx], 0, sizeof(struct nsdst) * (nsd->zonestatdesired - nsd->zonestatsize[idx])); } nsd->zonestatsize[idx] = nsd->zonestatdesired; #endif /* HAVE_MMAP */ } /* switchover to use the other array for the new children, that * briefly coexist with the old children. And we want to avoid them * both writing to the same statistics arrays. */ void server_zonestat_switch(struct nsd* nsd) { if(nsd->zonestatnow == nsd->zonestat[0]) { nsd->zonestatnow = nsd->zonestat[1]; nsd->zonestatsizenow = nsd->zonestatsize[1]; } else { nsd->zonestatnow = nsd->zonestat[0]; nsd->zonestatsizenow = nsd->zonestatsize[0]; } } #endif /* USE_ZONE_STATS */ static void cleanup_dname_compression_tables(void *ptr) { free(ptr); compressed_dname_offsets = NULL; compression_table_capacity = 0; } static void initialize_dname_compression_tables(struct nsd *nsd) { size_t needed = domain_table_count(nsd->db->domains) + 1; needed += EXTRA_DOMAIN_NUMBERS; if(compression_table_capacity < needed) { if(compressed_dname_offsets) { region_remove_cleanup(nsd->db->region, cleanup_dname_compression_tables, compressed_dname_offsets); free(compressed_dname_offsets); } compressed_dname_offsets = (uint16_t *) xmallocarray( needed, sizeof(uint16_t)); region_add_cleanup(nsd->db->region, cleanup_dname_compression_tables, compressed_dname_offsets); compression_table_capacity = needed; compression_table_size=domain_table_count(nsd->db->domains)+1; } memset(compressed_dname_offsets, 0, needed * sizeof(uint16_t)); compressed_dname_offsets[0] = QHEADERSZ; /* The original query name */ } /* create and bind sockets. */ static int server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works) { struct addrinfo* addr; size_t i; #if defined(SO_REUSEPORT) || defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT)) || defined(IP_FREEBIND) || defined(SO_BINDANY)) int on = 1; #endif /* UDP */ /* Make a socket... */ for (i = from; i < to; i++) { /* for reuseports copy socket specs of first entries */ addr = nsd->udp[i%nsd->ifs].addr; if (!addr) { nsd->udp[i].s = -1; continue; } nsd->udp[i].fam = (int)addr->ai_family; if ((nsd->udp[i].s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT && nsd->grab_ip6_optional) { log_msg(LOG_WARNING, "fallback to UDP4, no IPv6: not supported"); continue; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } #ifdef SO_REUSEPORT # ifdef SO_REUSEPORT_LB /* on FreeBSD 12 we have SO_REUSEPORT_LB that does loadbalance * like SO_REUSEPORT on Linux. This is what the users want * with the config option in nsd.conf; if we actually * need local address and port reuse they'll also need to * have SO_REUSEPORT set for them, assume it was _LB they want. */ if(nsd->reuseport && *reuseport_works && setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_REUSEPORT_LB, (void*)&on, (socklen_t)sizeof(on)) < 0) { if(verbosity >= 3 #ifdef ENOPROTOOPT || errno != ENOPROTOOPT #endif ) log_msg(LOG_ERR, "setsockopt(..., SO_REUSEPORT_LB, " "...) failed: %s", strerror(errno)); *reuseport_works = 0; } # else /* SO_REUSEPORT_LB */ if(nsd->reuseport && *reuseport_works && setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_REUSEPORT, (void*)&on, (socklen_t)sizeof(on)) < 0) { if(verbosity >= 3 #ifdef ENOPROTOOPT || errno != ENOPROTOOPT #endif ) log_msg(LOG_ERR, "setsockopt(..., SO_REUSEPORT, " "...) failed: %s", strerror(errno)); *reuseport_works = 0; } # endif /* SO_REUSEPORT_LB */ #else (void)reuseport_works; #endif /* SO_REUSEPORT */ #if defined(SO_RCVBUF) || defined(SO_SNDBUF) if(1) { int rcv = 1*1024*1024; int snd = 1*1024*1024; #ifdef SO_RCVBUF # ifdef SO_RCVBUFFORCE if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { if(errno != EPERM && errno != ENOBUFS) { log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUFFORCE, " "...) failed: %s", strerror(errno)); return -1; } # else if(1) { # endif /* SO_RCVBUFFORCE */ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { if(errno != ENOBUFS && errno != ENOSYS) { log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUF, " "...) failed: %s", strerror(errno)); return -1; } } } #endif /* SO_RCVBUF */ #ifdef SO_SNDBUF # ifdef SO_SNDBUFFORCE if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { if(errno != EPERM && errno != ENOBUFS) { log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUFFORCE, " "...) failed: %s", strerror(errno)); return -1; } # else if(1) { # endif /* SO_SNDBUFFORCE */ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { if(errno != ENOBUFS && errno != ENOSYS) { log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUF, " "...) failed: %s", strerror(errno)); return -1; } } } #endif /* SO_SNDBUF */ } #endif /* defined(SO_RCVBUF) || defined(SO_SNDBUF) */ #if defined(INET6) if (addr->ai_family == AF_INET6) { # if defined(IPV6_V6ONLY) if (setsockopt(nsd->udp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); return -1; } # endif # if defined(IPV6_USE_MIN_MTU) /* * There is no fragmentation of IPv6 datagrams * during forwarding in the network. Therefore * we do not send UDP datagrams larger than * the minimum IPv6 MTU of 1280 octets. The * EDNS0 message length can be larger if the * network stack supports IPV6_USE_MIN_MTU. */ if (setsockopt(nsd->udp[i].s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_USE_MIN_MTU, ...) failed: %s", strerror(errno)); return -1; } # elif defined(IPV6_MTU) /* * On Linux, PMTUD is disabled by default for datagrams * so set the MTU equal to the MIN MTU to get the same. */ on = IPV6_MIN_MTU; if (setsockopt(nsd->udp[i].s, IPPROTO_IPV6, IPV6_MTU, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_MTU, ...) failed: %s", strerror(errno)); return -1; } on = 1; # endif } #endif #if defined(AF_INET) if (addr->ai_family == AF_INET) { # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) int action = IP_PMTUDISC_DONT; if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_MTU_DISCOVER, &action, sizeof(action)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s", strerror(errno)); return -1; } # elif defined(IP_DONTFRAG) int off = 0; if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_DONTFRAG, &off, sizeof(off)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IP_DONTFRAG, ...) failed: %s", strerror(errno)); return -1; } # endif } #endif /* set it nonblocking */ /* otherwise, on OSes with thundering herd problems, the UDP recv could block NSD after select returns readable. */ if (fcntl(nsd->udp[i].s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl udp: %s", strerror(errno)); } /* Bind it... */ if (nsd->options->ip_freebind) { #ifdef IP_FREEBIND if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,IP_FREEBIND, ...) failed for udp: %s", strerror(errno)); } #endif /* IP_FREEBIND */ } if (nsd->options->ip_transparent) { #ifdef IP_TRANSPARENT if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,IP_TRANSPARENT, ...) failed for udp: %s", strerror(errno)); } #endif /* IP_TRANSPARENT */ #ifdef SO_BINDANY if (setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,SO_BINDANY, ...) failed for udp: %s", strerror(errno)); } #endif /* SO_BINDANY */ } if ( bind(nsd->udp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind udp socket: %s", strerror(errno)); return -1; } } /* TCP */ /* Make a socket... */ for (i = from; i < to; i++) { /* for reuseports copy socket specs of first entries */ addr = nsd->tcp[i%nsd->ifs].addr; if (!addr) { nsd->tcp[i].s = -1; continue; } nsd->tcp[i].fam = (int)addr->ai_family; /* turn off REUSEPORT for TCP by copying the socket fd */ if(i >= nsd->ifs) { nsd->tcp[i].s = nsd->tcp[i%nsd->ifs].s; continue; } if ((nsd->tcp[i].s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT && nsd->grab_ip6_optional) { log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); continue; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } #ifdef SO_REUSEPORT if(nsd->reuseport && *reuseport_works && setsockopt(nsd->tcp[i].s, SOL_SOCKET, SO_REUSEPORT, (void*)&on, (socklen_t)sizeof(on)) < 0) { if(verbosity >= 3 #ifdef ENOPROTOOPT || errno != ENOPROTOOPT #endif ) log_msg(LOG_ERR, "setsockopt(..., SO_REUSEPORT, " "...) failed: %s", strerror(errno)); *reuseport_works = 0; } #endif /* SO_REUSEPORT */ #ifdef SO_REUSEADDR if (setsockopt(nsd->tcp[i].s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); } #endif /* SO_REUSEADDR */ #if defined(INET6) if (addr->ai_family == AF_INET6) { # if defined(IPV6_V6ONLY) if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); return -1; } # endif # if defined(IPV6_USE_MIN_MTU) /* * Use minimum MTU to minimize delays learning working * PMTU when communicating through a tunnel. */ if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_USE_MIN_MTU, ...) failed: %s", strerror(errno)); return -1; } # elif defined(IPV6_MTU) /* * On Linux, PMTUD is disabled by default for datagrams * so set the MTU equal to the MIN MTU to get the same. */ on = IPV6_MIN_MTU; if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_MTU, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_MTU, ...) failed: %s", strerror(errno)); return -1; } on = 1; # endif } #endif /* set maximum segment size to tcp socket */ if(nsd->tcp_mss > 0) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(nsd->tcp[i].s, IPPROTO_TCP, TCP_MAXSEG, (void*)&nsd->tcp_mss, sizeof(nsd->tcp_mss)) < 0) { log_msg(LOG_ERR, "setsockopt(...,TCP_MAXSEG,...)" " failed for tcp: %s", strerror(errno)); } #else log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported"); #endif /* defined(IPPROTO_TCP) && defined(TCP_MAXSEG) */ } /* set it nonblocking */ /* (StevensUNP p463), if tcp listening socket is blocking, then it may block in accept, even if select() says readable. */ if (fcntl(nsd->tcp[i].s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno)); } /* Bind it... */ if (nsd->options->ip_freebind) { #ifdef IP_FREEBIND if (setsockopt(nsd->tcp[i].s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,IP_FREEBIND, ...) failed for tcp: %s", strerror(errno)); } #endif /* IP_FREEBIND */ } if (nsd->options->ip_transparent) { #ifdef IP_TRANSPARENT if (setsockopt(nsd->tcp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,IP_TRANSPARENT, ...) failed for tcp: %s", strerror(errno)); } #endif /* IP_TRANSPARENT */ #ifdef SO_BINDANY if (setsockopt(nsd->tcp[i].s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(...,SO_BINDANY, ...) failed for tcp: %s", strerror(errno)); } #endif /* SO_BINDANY */ } if( bind(nsd->tcp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); return -1; } /* Listen to it... */ if (listen(nsd->tcp[i].s, TCP_BACKLOG) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); return -1; } } return 0; } /* * Initialize the server, reuseport, create and bind the sockets. */ int server_init(struct nsd *nsd) { int reuseport_successful = 1; /* see if reuseport works in OS */ if(nsd->reuseport) { /* increase the size of the udp and tcp interface arrays, * there are going to be separate interface file descriptors * for every server instance */ nsd->udp = xrealloc(nsd->udp, (nsd->ifs*nsd->reuseport)* sizeof(*nsd->udp)); nsd->tcp = xrealloc(nsd->tcp, (nsd->ifs*nsd->reuseport)* sizeof(*nsd->tcp)); memset(&nsd->udp[nsd->ifs], 0, sizeof(*nsd->udp)* (nsd->ifs*(nsd->reuseport-1))); memset(&nsd->tcp[nsd->ifs], 0, sizeof(*nsd->tcp)* (nsd->ifs*(nsd->reuseport-1))); } /* open the server interface ports */ if(server_init_ifs(nsd, 0, nsd->ifs, &reuseport_successful) == -1) return -1; /* continue to open the remaining reuseport ports */ if(nsd->reuseport && reuseport_successful) { if(server_init_ifs(nsd, nsd->ifs, nsd->ifs*nsd->reuseport, &reuseport_successful) == -1) return -1; nsd->ifs *= nsd->reuseport; } else { nsd->reuseport = 0; } return 0; } /* * Prepare the server for take off. * */ int server_prepare(struct nsd *nsd) { #ifdef RATELIMIT /* set secret modifier for hashing (udb ptr buckets and rate limits) */ #ifdef HAVE_ARC4RANDOM hash_set_raninit(arc4random()); #else uint32_t v = getpid() ^ time(NULL); srandom((unsigned long)v); if(RAND_status() && RAND_bytes((unsigned char*)&v, sizeof(v)) > 0) hash_set_raninit(v); else hash_set_raninit(random()); #endif rrl_mmap_init(nsd->child_count, nsd->options->rrl_size, nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit, nsd->options->rrl_slip, nsd->options->rrl_ipv4_prefix_length, nsd->options->rrl_ipv6_prefix_length); #endif /* RATELIMIT */ /* Open the database... */ if ((nsd->db = namedb_open(nsd->dbfile, nsd->options)) == NULL) { log_msg(LOG_ERR, "unable to open the database %s: %s", nsd->dbfile, strerror(errno)); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif xfrd_del_tempdir(nsd); return -1; } /* check if zone files have been modified */ /* NULL for taskudb because we send soainfo in a moment, batched up, * for all zones */ if(nsd->options->zonefiles_check || (nsd->options->database == NULL || nsd->options->database[0] == 0)) namedb_check_zonefiles(nsd, nsd->options, NULL, NULL); zonestatid_tree_set(nsd); compression_table_capacity = 0; initialize_dname_compression_tables(nsd); #ifdef BIND8_STATS /* Initialize times... */ time(&nsd->st.boot); set_bind8_alarm(nsd); #endif /* BIND8_STATS */ return 0; } /* * Fork the required number of servers. */ static int server_start_children(struct nsd *nsd, region_type* region, netio_type* netio, int* xfrd_sock_p) { size_t i; /* Start all child servers initially. */ for (i = 0; i < nsd->child_count; ++i) { nsd->children[i].pid = 0; } return restart_child_servers(nsd, region, netio, xfrd_sock_p); } void server_close_all_sockets(struct nsd_socket sockets[], size_t n) { size_t i; /* Close all the sockets... */ for (i = 0; i < n; ++i) { if (sockets[i].s != -1) { close(sockets[i].s); if(sockets[i].addr) freeaddrinfo(sockets[i].addr); sockets[i].s = -1; } } } /* * Close the sockets, shutdown the server and exit. * Does not return. * */ void server_shutdown(struct nsd *nsd) { size_t i; server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); /* CHILD: close command channel to parent */ if(nsd->this_child && nsd->this_child->parent_fd != -1) { close(nsd->this_child->parent_fd); nsd->this_child->parent_fd = -1; } /* SERVER: close command channels to children */ if(!nsd->this_child) { for(i=0; i < nsd->child_count; ++i) if(nsd->children[i].child_fd != -1) { close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; } } tsig_finalize(); #ifdef HAVE_SSL daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */ #endif #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_mmap_deinit_keep_mmap(); #endif #ifdef USE_DNSTAP dt_collector_destroy(nsd->dt_collector, nsd); #endif udb_base_free_keep_mmap(nsd->task[0]); udb_base_free_keep_mmap(nsd->task[1]); namedb_close_udb(nsd->db); /* keeps mmap */ namedb_close(nsd->db); nsd_options_destroy(nsd->options); region_destroy(nsd->region); #endif log_finalize(); exit(0); } void server_prepare_xfrd(struct nsd* nsd) { char tmpfile[256]; /* create task mmaps */ nsd->mytask = 0; snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.0", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[0] = task_file_create(tmpfile); if(!nsd->task[0]) { #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif xfrd_del_tempdir(nsd); exit(1); } snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.1", nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[1] = task_file_create(tmpfile); if(!nsd->task[1]) { unlink(nsd->task[0]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif xfrd_del_tempdir(nsd); exit(1); } assert(udb_base_get_userdata(nsd->task[0])->data == 0); assert(udb_base_get_userdata(nsd->task[1])->data == 0); /* create xfrd listener structure */ nsd->xfrd_listener = region_alloc(nsd->region, sizeof(netio_handler_type)); nsd->xfrd_listener->user_data = (struct ipc_handler_conn_data*) region_alloc(nsd->region, sizeof(struct ipc_handler_conn_data)); nsd->xfrd_listener->fd = -1; ((struct ipc_handler_conn_data*)nsd->xfrd_listener->user_data)->nsd = nsd; ((struct ipc_handler_conn_data*)nsd->xfrd_listener->user_data)->conn = xfrd_tcp_create(nsd->region, QIOBUFSZ); } void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active) { pid_t pid; int sockets[2] = {0,0}; struct ipc_handler_conn_data *data; if(nsd->xfrd_listener->fd != -1) close(nsd->xfrd_listener->fd); if(del_db) { /* recreate taskdb that xfrd was using, it may be corrupt */ /* we (or reload) use nsd->mytask, and xfrd uses the other */ char* tmpfile = nsd->task[1-nsd->mytask]->fname; nsd->task[1-nsd->mytask]->fname = NULL; /* free alloc already, so udb does not shrink itself */ udb_alloc_delete(nsd->task[1-nsd->mytask]->alloc); nsd->task[1-nsd->mytask]->alloc = NULL; udb_base_free(nsd->task[1-nsd->mytask]); /* create new file, overwrite the old one */ nsd->task[1-nsd->mytask] = task_file_create(tmpfile); free(tmpfile); } if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { log_msg(LOG_ERR, "startxfrd failed on socketpair: %s", strerror(errno)); return; } pid = fork(); switch (pid) { case -1: log_msg(LOG_ERR, "fork xfrd failed: %s", strerror(errno)); break; default: /* PARENT: close first socket, use second one */ close(sockets[0]); if (fcntl(sockets[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } if(del_db) xfrd_free_namedb(nsd); /* use other task than I am using, since if xfrd died and is * restarted, the reload is using nsd->mytask */ nsd->mytask = 1 - nsd->mytask; xfrd_init(sockets[1], nsd, del_db, reload_active, pid); /* ENOTREACH */ break; case 0: /* CHILD: close second socket, use first one */ close(sockets[1]); if (fcntl(sockets[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } nsd->xfrd_listener->fd = sockets[0]; break; } /* server-parent only */ nsd->xfrd_listener->timeout = NULL; nsd->xfrd_listener->event_types = NETIO_EVENT_READ; nsd->xfrd_listener->event_handler = parent_handle_xfrd_command; /* clear ongoing ipc reads */ data = (struct ipc_handler_conn_data *) nsd->xfrd_listener->user_data; data->conn->is_reading = 0; } /** add all soainfo to taskdb */ static void add_all_soa_to_task(struct nsd* nsd, struct udb_base* taskudb) { struct radnode* n; udb_ptr task_last; /* last task, mytask is empty so NULL */ /* add all SOA INFO to mytask */ udb_ptr_init(&task_last, taskudb); for(n=radix_first(nsd->db->zonetree); n; n=radix_next(n)) { task_new_soainfo(taskudb, &task_last, (zone_type*)n->elem, 0); } udb_ptr_unlink(&task_last, taskudb); } void server_send_soa_xfrd(struct nsd* nsd, int shortsoa) { /* normally this exchanges the SOA from nsd->xfrd and the expire back. * parent fills one taskdb with soas, xfrd fills other with expires. * then they exchange and process. * shortsoa: xfrd crashes and needs to be restarted and one taskdb * may be in use by reload. Fill SOA in taskdb and give to xfrd. * expire notifications can be sent back via a normal reload later * (xfrd will wait for current running reload to finish if any). */ sig_atomic_t cmd = 0; pid_t mypid; int xfrd_sock = nsd->xfrd_listener->fd; struct udb_base* taskudb = nsd->task[nsd->mytask]; udb_ptr t; if(!shortsoa) { if(nsd->signal_hint_shutdown) { shutdown: log_msg(LOG_WARNING, "signal received, shutting down..."); server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); #ifdef HAVE_SSL daemon_remote_close(nsd->rc); #endif /* Unlink it if possible... */ unlinkpid(nsd->pidfile); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif /* write the nsd.db to disk, wait for it to complete */ udb_base_sync(nsd->db->udb, 1); udb_base_close(nsd->db->udb); server_shutdown(nsd); exit(0); } } if(shortsoa) { /* put SOA in xfrd task because mytask may be in use */ taskudb = nsd->task[1-nsd->mytask]; } add_all_soa_to_task(nsd, taskudb); if(!shortsoa) { /* wait for xfrd to signal task is ready, RELOAD signal */ if(block_read(nsd, xfrd_sock, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD) { log_msg(LOG_ERR, "did not get start signal from xfrd"); exit(1); } if(nsd->signal_hint_shutdown) { goto shutdown; } } /* give xfrd our task, signal it with RELOAD_DONE */ task_process_sync(taskudb); cmd = NSD_RELOAD_DONE; if(!write_socket(xfrd_sock, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending soa end from reload %d to xfrd: %s", (int)nsd->pid, strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } if(!shortsoa) { /* process the xfrd task works (expiry data) */ nsd->mytask = 1 - nsd->mytask; taskudb = nsd->task[nsd->mytask]; task_remap(taskudb); udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); while(!udb_ptr_is_null(&t)) { task_process_expire(nsd->db, TASKLIST(&t)); udb_ptr_set_rptr(&t, taskudb, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, taskudb); task_clear(taskudb); /* tell xfrd that the task is emptied, signal with RELOAD_DONE */ cmd = NSD_RELOAD_DONE; if(!write_socket(xfrd_sock, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending soa end from reload %d to xfrd: %s", (int)nsd->pid, strerror(errno)); } } } /* pass timeout=-1 for blocking. Returns size, 0, -1(err), or -2(timeout) */ ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout) { uint8_t* buf = (uint8_t*) p; ssize_t total = 0; struct pollfd fd; memset(&fd, 0, sizeof(fd)); fd.fd = s; fd.events = POLLIN; while( total < sz) { ssize_t ret; ret = poll(&fd, 1, (timeout==-1)?-1:timeout*1000); if(ret == -1) { if(errno == EAGAIN) /* blocking read */ continue; if(errno == EINTR) { if(nsd && (nsd->signal_hint_quit || nsd->signal_hint_shutdown)) return -1; /* other signals can be handled later */ continue; } /* some error */ return -1; } if(ret == 0) { /* operation timed out */ return -2; } ret = read(s, buf+total, sz-total); if(ret == -1) { if(errno == EAGAIN) /* blocking read */ continue; if(errno == EINTR) { if(nsd && (nsd->signal_hint_quit || nsd->signal_hint_shutdown)) return -1; /* other signals can be handled later */ continue; } /* some error */ return -1; } if(ret == 0) { /* closed connection! */ return 0; } total += ret; } return total; } static void reload_process_tasks(struct nsd* nsd, udb_ptr* last_task, int cmdsocket) { sig_atomic_t cmd = NSD_QUIT_SYNC; udb_ptr t, next; udb_base* u = nsd->task[nsd->mytask]; udb_ptr_init(&next, u); udb_ptr_new(&t, u, udb_base_get_userdata(u)); udb_base_set_userdata(u, 0); while(!udb_ptr_is_null(&t)) { /* store next in list so this one can be deleted or reused */ udb_ptr_set_rptr(&next, u, &TASKLIST(&t)->next); udb_rptr_zero(&TASKLIST(&t)->next, u); /* process task t */ /* append results for task t and update last_task */ task_process_in_reload(nsd, u, last_task, &t); /* go to next */ udb_ptr_set_ptr(&t, u, &next); /* if the parent has quit, we must quit too, poll the fd for cmds */ if(block_read(nsd, cmdsocket, &cmd, sizeof(cmd), 0) == sizeof(cmd)) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", (int)cmd)); if(cmd == NSD_QUIT) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd")); /* sync to disk (if needed) */ udb_base_sync(nsd->db->udb, 0); /* unlink files of remainder of tasks */ while(!udb_ptr_is_null(&t)) { if(TASKLIST(&t)->task_type == task_apply_xfr) { xfrd_unlink_xfrfile(nsd, TASKLIST(&t)->yesno); } udb_ptr_set_rptr(&t, u, &TASKLIST(&t)->next); } udb_ptr_unlink(&t, u); udb_ptr_unlink(&next, u); exit(0); } } } udb_ptr_unlink(&t, u); udb_ptr_unlink(&next, u); } #ifdef BIND8_STATS static void parent_send_stats(struct nsd* nsd, int cmdfd) { size_t i; if(!write_socket(cmdfd, &nsd->st, sizeof(nsd->st))) { log_msg(LOG_ERR, "could not write stats to reload"); return; } for(i=0; ichild_count; i++) if(!write_socket(cmdfd, &nsd->children[i].query_count, sizeof(stc_type))) { log_msg(LOG_ERR, "could not write stats to reload"); return; } } static void reload_do_stats(int cmdfd, struct nsd* nsd, udb_ptr* last) { struct nsdst s; stc_type* p; size_t i; if(block_read(nsd, cmdfd, &s, sizeof(s), RELOAD_SYNC_TIMEOUT) != sizeof(s)) { log_msg(LOG_ERR, "could not read stats from oldpar"); return; } s.db_disk = (nsd->db->udb?nsd->db->udb->base_size:0); s.db_mem = region_get_mem(nsd->db->region); p = (stc_type*)task_new_stat_info(nsd->task[nsd->mytask], last, &s, nsd->child_count); if(!p) return; for(i=0; ichild_count; i++) { if(block_read(nsd, cmdfd, p++, sizeof(stc_type), 1)!= sizeof(stc_type)) return; } } #endif /* BIND8_STATS */ /* * Reload the database, stop parent, re-fork children and continue. * as server_main. */ static void server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, int cmdsocket) { pid_t mypid; sig_atomic_t cmd = NSD_QUIT_SYNC; int ret; udb_ptr last_task; struct sigaction old_sigchld, ign_sigchld; /* ignore SIGCHLD from the previous server_main that used this pid */ memset(&ign_sigchld, 0, sizeof(ign_sigchld)); ign_sigchld.sa_handler = SIG_IGN; sigaction(SIGCHLD, &ign_sigchld, &old_sigchld); /* see what tasks we got from xfrd */ task_remap(nsd->task[nsd->mytask]); udb_ptr_init(&last_task, nsd->task[nsd->mytask]); udb_compact_inhibited(nsd->db->udb, 1); reload_process_tasks(nsd, &last_task, cmdsocket); udb_compact_inhibited(nsd->db->udb, 0); udb_compact(nsd->db->udb); #ifndef NDEBUG if(nsd_debug_level >= 1) region_log_stats(nsd->db->region); #endif /* NDEBUG */ /* sync to disk (if needed) */ udb_base_sync(nsd->db->udb, 0); initialize_dname_compression_tables(nsd); #ifdef BIND8_STATS /* Restart dumping stats if required. */ time(&nsd->st.boot); set_bind8_alarm(nsd); #endif #ifdef USE_ZONE_STATS server_zonestat_realloc(nsd); /* realloc for new children */ server_zonestat_switch(nsd); #endif /* listen for the signals of failed children again */ sigaction(SIGCHLD, &old_sigchld, NULL); /* Start new child processes */ if (server_start_children(nsd, server_region, netio, &nsd-> xfrd_listener->fd) != 0) { send_children_quit(nsd); exit(1); } /* if the parent has quit, we must quit too, poll the fd for cmds */ if(block_read(nsd, cmdsocket, &cmd, sizeof(cmd), 0) == sizeof(cmd)) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", (int)cmd)); if(cmd == NSD_QUIT) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd")); send_children_quit(nsd); exit(0); } } /* Send quit command to parent: blocking, wait for receipt. */ do { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending command from reload to oldnsd: %s", strerror(errno)); } /* blocking: wait for parent to really quit. (it sends RELOAD as ack) */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc wait for ack main")); ret = block_read(nsd, cmdsocket, &cmd, sizeof(cmd), RELOAD_SYNC_TIMEOUT); if(ret == -2) { DEBUG(DEBUG_IPC, 1, (LOG_ERR, "reload timeout QUITSYNC. retry")); } } while (ret == -2); if(ret == -1) { log_msg(LOG_ERR, "reload: could not wait for parent to quit: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d %d", ret, (int)cmd)); if(cmd == NSD_QUIT) { /* small race condition possible here, parent got quit cmd. */ send_children_quit(nsd); exit(1); } assert(ret==-1 || ret == 0 || cmd == NSD_RELOAD); #ifdef BIND8_STATS reload_do_stats(cmdsocket, nsd, &last_task); #endif udb_ptr_unlink(&last_task, nsd->task[nsd->mytask]); task_process_sync(nsd->task[nsd->mytask]); #ifdef USE_ZONE_STATS server_zonestat_realloc(nsd); /* realloc for next children */ #endif /* send soainfo to the xfrd process, signal it that reload is done, * it picks up the taskudb */ cmd = NSD_RELOAD_DONE; if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending reload_done xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } /* try to reopen file */ if (nsd->file_rotation_ok) log_reopen(nsd->log_filename, 1); /* exit reload, continue as new server_main */ } /* * Get the mode depending on the signal hints that have been received. * Multiple signal hints can be received and will be handled in turn. */ static sig_atomic_t server_signal_mode(struct nsd *nsd) { if(nsd->signal_hint_quit) { nsd->signal_hint_quit = 0; return NSD_QUIT; } else if(nsd->signal_hint_shutdown) { nsd->signal_hint_shutdown = 0; return NSD_SHUTDOWN; } else if(nsd->signal_hint_child) { nsd->signal_hint_child = 0; return NSD_REAP_CHILDREN; } else if(nsd->signal_hint_reload) { nsd->signal_hint_reload = 0; return NSD_RELOAD; } else if(nsd->signal_hint_reload_hup) { nsd->signal_hint_reload_hup = 0; return NSD_RELOAD_REQ; } else if(nsd->signal_hint_stats) { nsd->signal_hint_stats = 0; #ifdef BIND8_STATS set_bind8_alarm(nsd); #endif return NSD_STATS; } else if(nsd->signal_hint_statsusr) { nsd->signal_hint_statsusr = 0; return NSD_STATS; } return NSD_RUN; } /* * The main server simply waits for signals and child processes to * terminate. Child processes are restarted as necessary. */ void server_main(struct nsd *nsd) { region_type *server_region = region_create(xalloc, free); netio_type *netio = netio_create(server_region); netio_handler_type reload_listener; int reload_sockets[2] = {-1, -1}; struct timespec timeout_spec; int status; pid_t child_pid; pid_t reload_pid = -1; sig_atomic_t mode; /* Ensure we are the main process */ assert(nsd->server_kind == NSD_SERVER_MAIN); /* Add listener for the XFRD process */ netio_add_handler(netio, nsd->xfrd_listener); /* Start the child processes that handle incoming queries */ if (server_start_children(nsd, server_region, netio, &nsd->xfrd_listener->fd) != 0) { send_children_quit(nsd); exit(1); } reload_listener.fd = -1; /* This_child MUST be 0, because this is the parent process */ assert(nsd->this_child == 0); /* Run the server until we get a shutdown signal */ while ((mode = nsd->mode) != NSD_SHUTDOWN) { /* Did we receive a signal that changes our mode? */ if(mode == NSD_RUN) { nsd->mode = mode = server_signal_mode(nsd); } switch (mode) { case NSD_RUN: /* see if any child processes terminated */ while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { int is_child = delete_child_pid(nsd, child_pid); if (is_child != -1 && nsd->children[is_child].need_to_exit) { if(nsd->children[is_child].child_fd == -1) nsd->children[is_child].has_exited = 1; parent_check_all_children_exited(nsd); } else if(is_child != -1) { log_msg(LOG_WARNING, "server %d died unexpectedly with status %d, restarting", (int) child_pid, status); restart_child_servers(nsd, server_region, netio, &nsd->xfrd_listener->fd); } else if (child_pid == reload_pid) { sig_atomic_t cmd = NSD_RELOAD_DONE; pid_t mypid; log_msg(LOG_WARNING, "Reload process %d failed with status %d, continuing with old database", (int) child_pid, status); reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; task_process_sync(nsd->task[nsd->mytask]); /* inform xfrd reload attempt ended */ if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems " "sending SOAEND to xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } } else if(status != 0) { /* check for status, because we get * the old-servermain because reload * is the process-parent of old-main, * and we get older server-processes * that are exiting after a reload */ log_msg(LOG_WARNING, "process %d terminated with status %d", (int) child_pid, status); } } if (child_pid == -1) { if (errno == EINTR) { continue; } if (errno != ECHILD) log_msg(LOG_WARNING, "wait failed: %s", strerror(errno)); } if (nsd->mode != NSD_RUN) break; /* timeout to collect processes. In case no sigchild happens. */ timeout_spec.tv_sec = 60; timeout_spec.tv_nsec = 0; /* listen on ports, timeout for collecting terminated children */ if(netio_dispatch(netio, &timeout_spec, 0) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "netio_dispatch failed: %s", strerror(errno)); } } if(nsd->restart_children) { restart_child_servers(nsd, server_region, netio, &nsd->xfrd_listener->fd); nsd->restart_children = 0; } if(nsd->reload_failed) { sig_atomic_t cmd = NSD_RELOAD_DONE; pid_t mypid; nsd->reload_failed = 0; log_msg(LOG_WARNING, "Reload process %d failed, continuing with old database", (int) reload_pid); reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; task_process_sync(nsd->task[nsd->mytask]); /* inform xfrd reload attempt ended */ if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems " "sending SOAEND to xfrd: %s", strerror(errno)); } mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } } break; case NSD_RELOAD_REQ: { sig_atomic_t cmd = NSD_RELOAD_REQ; log_msg(LOG_WARNING, "SIGHUP received, reloading..."); DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send reload_req to xfrd")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send " "reload_req to xfrd: %s", strerror(errno)); } nsd->mode = NSD_RUN; } break; case NSD_RELOAD: /* Continue to run nsd after reload */ nsd->mode = NSD_RUN; DEBUG(DEBUG_IPC,1, (LOG_INFO, "reloading...")); if (reload_pid != -1) { log_msg(LOG_WARNING, "Reload already in progress (pid = %d)", (int) reload_pid); break; } /* switch the mytask to keep track of who owns task*/ nsd->mytask = 1 - nsd->mytask; if (socketpair(AF_UNIX, SOCK_STREAM, 0, reload_sockets) == -1) { log_msg(LOG_ERR, "reload failed on socketpair: %s", strerror(errno)); reload_pid = -1; break; } /* Do actual reload */ reload_pid = fork(); switch (reload_pid) { case -1: log_msg(LOG_ERR, "fork failed: %s", strerror(errno)); break; default: /* PARENT */ close(reload_sockets[0]); server_reload(nsd, server_region, netio, reload_sockets[1]); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload exited to become new main")); close(reload_sockets[1]); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload closed")); /* drop stale xfrd ipc data */ ((struct ipc_handler_conn_data*)nsd-> xfrd_listener->user_data) ->conn->is_reading = 0; reload_pid = -1; reload_listener.fd = -1; reload_listener.event_types = NETIO_EVENT_NONE; DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload resetup; run")); break; case 0: /* CHILD */ /* server_main keep running until NSD_QUIT_SYNC * received from reload. */ close(reload_sockets[1]); reload_listener.fd = reload_sockets[0]; reload_listener.timeout = NULL; reload_listener.user_data = nsd; reload_listener.event_types = NETIO_EVENT_READ; reload_listener.event_handler = parent_handle_reload_command; /* listens to Quit */ netio_add_handler(netio, &reload_listener); reload_pid = getppid(); break; } break; case NSD_QUIT_SYNC: /* synchronisation of xfrd, parent and reload */ if(!nsd->quit_sync_done && reload_listener.fd != -1) { sig_atomic_t cmd = NSD_RELOAD; /* stop xfrd ipc writes in progress */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send indication reload")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send reload " "indication to xfrd: %s", strerror(errno)); } /* wait for ACK from xfrd */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: wait ipc reply xfrd")); nsd->quit_sync_done = 1; } nsd->mode = NSD_RUN; break; case NSD_QUIT: /* silent shutdown during reload */ if(reload_listener.fd != -1) { /* acknowledge the quit, to sync reload that we will really quit now */ sig_atomic_t cmd = NSD_RELOAD; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc ack reload")); if(!write_socket(reload_listener.fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: " "could not ack quit: %s", strerror(errno)); } #ifdef BIND8_STATS parent_send_stats(nsd, reload_listener.fd); #endif /* BIND8_STATS */ close(reload_listener.fd); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "server_main: shutdown sequence")); /* only quit children after xfrd has acked */ send_children_quit(nsd); #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(server_region); #endif server_shutdown(nsd); /* ENOTREACH */ break; case NSD_SHUTDOWN: break; case NSD_REAP_CHILDREN: /* continue; wait for child in run loop */ nsd->mode = NSD_RUN; break; case NSD_STATS: #ifdef BIND8_STATS set_children_stats(nsd); #endif nsd->mode = NSD_RUN; break; default: log_msg(LOG_WARNING, "NSD main server mode invalid: %d", (int)nsd->mode); nsd->mode = NSD_RUN; break; } } log_msg(LOG_WARNING, "signal received, shutting down..."); /* close opened ports to avoid race with restart of nsd */ server_close_all_sockets(nsd->udp, nsd->ifs); server_close_all_sockets(nsd->tcp, nsd->ifs); #ifdef HAVE_SSL daemon_remote_close(nsd->rc); #endif send_children_quit_and_wait(nsd); /* Unlink it if possible... */ unlinkpid(nsd->pidfile); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif #ifdef USE_DNSTAP dt_collector_close(nsd->dt_collector, nsd); #endif if(reload_listener.fd != -1) { sig_atomic_t cmd = NSD_QUIT; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send quit to reload-process")); if(!write_socket(reload_listener.fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send quit to reload: %s", strerror(errno)); } fsync(reload_listener.fd); close(reload_listener.fd); /* wait for reload to finish processing */ while(1) { if(waitpid(reload_pid, NULL, 0) == -1) { if(errno == EINTR) continue; if(errno == ECHILD) break; log_msg(LOG_ERR, "waitpid(reload %d): %s", (int)reload_pid, strerror(errno)); } break; } } if(nsd->xfrd_listener->fd != -1) { /* complete quit, stop xfrd */ sig_atomic_t cmd = NSD_QUIT; DEBUG(DEBUG_IPC,1, (LOG_INFO, "main: ipc send quit to xfrd")); if(!write_socket(nsd->xfrd_listener->fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "server_main: could not send quit to xfrd: %s", strerror(errno)); } fsync(nsd->xfrd_listener->fd); close(nsd->xfrd_listener->fd); (void)kill(nsd->pid, SIGTERM); } #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(server_region); #endif /* write the nsd.db to disk, wait for it to complete */ udb_base_sync(nsd->db->udb, 1); udb_base_close(nsd->db->udb); server_shutdown(nsd); } static query_state_type server_process_query(struct nsd *nsd, struct query *query) { return query_process(query, nsd); } static query_state_type server_process_query_udp(struct nsd *nsd, struct query *query) { #ifdef RATELIMIT if(query_process(query, nsd) != QUERY_DISCARDED) { if(rrl_process_query(query)) return rrl_slip(query); else return QUERY_PROCESSED; } return QUERY_DISCARDED; #else return query_process(query, nsd); #endif } struct event_base* nsd_child_event_base(void) { struct event_base* base; #ifdef USE_MINI_EVENT static time_t secs; static struct timeval now; base = event_init(&secs, &now); #else # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) /* libev */ base = (struct event_base *)ev_default_loop(EVFLAG_AUTO); # else /* libevent */ # ifdef HAVE_EVENT_BASE_NEW base = event_base_new(); # else base = event_init(); # endif # endif #endif return base; } /* * Serve DNS requests. */ void server_child(struct nsd *nsd) { size_t i, from, numifs; region_type *server_region = region_create(xalloc, free); struct event_base* event_base = nsd_child_event_base(); query_type *udp_query; sig_atomic_t mode; if(!event_base) { log_msg(LOG_ERR, "nsd server could not create event base"); exit(1); } nsd->event_base = event_base; nsd->server_region = server_region; #ifdef RATELIMIT rrl_init(nsd->this_child->child_num); #endif assert(nsd->server_kind != NSD_SERVER_MAIN); DEBUG(DEBUG_IPC, 2, (LOG_INFO, "child process started")); if (!(nsd->server_kind & NSD_SERVER_TCP)) { server_close_all_sockets(nsd->tcp, nsd->ifs); } if (!(nsd->server_kind & NSD_SERVER_UDP)) { server_close_all_sockets(nsd->udp, nsd->ifs); } if (nsd->this_child->parent_fd != -1) { struct event *handler; struct ipc_handler_conn_data* user_data = (struct ipc_handler_conn_data*)region_alloc( server_region, sizeof(struct ipc_handler_conn_data)); user_data->nsd = nsd; user_data->conn = xfrd_tcp_create(server_region, QIOBUFSZ); handler = (struct event*) region_alloc( server_region, sizeof(*handler)); event_set(handler, nsd->this_child->parent_fd, EV_PERSIST| EV_READ, child_handle_parent_command, user_data); if(event_base_set(event_base, handler) != 0) log_msg(LOG_ERR, "nsd ipcchild: event_base_set failed"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "nsd ipcchild: event_add failed"); } if(nsd->reuseport) { numifs = nsd->ifs / nsd->reuseport; from = numifs * nsd->this_child->child_num; if(from+numifs > nsd->ifs) { /* should not happen */ from = 0; numifs = nsd->ifs; } } else { from = 0; numifs = nsd->ifs; } if (nsd->server_kind & NSD_SERVER_UDP) { #if (defined(NONBLOCKING_IS_BROKEN) || !defined(HAVE_RECVMMSG)) udp_query = query_create(server_region, compressed_dname_offsets, compression_table_size, compressed_dnames); #else udp_query = NULL; memset(msgs, 0, sizeof(msgs)); for (i = 0; i < NUM_RECV_PER_SELECT; i++) { queries[i] = query_create(server_region, compressed_dname_offsets, compression_table_size, compressed_dnames); query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_base = buffer_begin(queries[i]->packet); iovecs[i].iov_len = buffer_remaining(queries[i]->packet);; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; msgs[i].msg_hdr.msg_name = &queries[i]->addr; msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; } #endif for (i = from; i < from+numifs; ++i) { struct udp_handler_data *data; struct event *handler; data = (struct udp_handler_data *) region_alloc( server_region, sizeof(struct udp_handler_data)); data->query = udp_query; data->nsd = nsd; data->socket = &nsd->udp[i]; handler = (struct event*) region_alloc( server_region, sizeof(*handler)); event_set(handler, nsd->udp[i].s, EV_PERSIST|EV_READ, handle_udp, data); if(event_base_set(event_base, handler) != 0) log_msg(LOG_ERR, "nsd udp: event_base_set failed"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "nsd udp: event_add failed"); } } /* * Keep track of all the TCP accept handlers so we can enable * and disable them based on the current number of active TCP * connections. */ tcp_accept_handler_count = numifs; tcp_accept_handlers = (struct tcp_accept_handler_data*) region_alloc_array(server_region, numifs, sizeof(*tcp_accept_handlers)); if (nsd->server_kind & NSD_SERVER_TCP) { for (i = from; i < numifs; ++i) { struct event *handler = &tcp_accept_handlers[i-from].event; struct tcp_accept_handler_data* data = &tcp_accept_handlers[i-from]; data->nsd = nsd; data->socket = &nsd->tcp[i]; event_set(handler, nsd->tcp[i].s, EV_PERSIST|EV_READ, handle_tcp_accept, data); if(event_base_set(event_base, handler) != 0) log_msg(LOG_ERR, "nsd tcp: event_base_set failed"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "nsd tcp: event_add failed"); data->event_added = 1; } } else tcp_accept_handler_count = 0; /* The main loop... */ while ((mode = nsd->mode) != NSD_QUIT) { if(mode == NSD_RUN) nsd->mode = mode = server_signal_mode(nsd); /* Do we need to do the statistics... */ if (mode == NSD_STATS) { #ifdef BIND8_STATS int p = nsd->st.period; nsd->st.period = 1; /* force stats printout */ /* Dump the statistics */ bind8_stats(nsd); nsd->st.period = p; #else /* !BIND8_STATS */ log_msg(LOG_NOTICE, "Statistics support not enabled at compile time."); #endif /* BIND8_STATS */ nsd->mode = NSD_RUN; } else if (mode == NSD_REAP_CHILDREN) { /* got signal, notify parent. parent reaps terminated children. */ if (nsd->this_child->parent_fd != -1) { sig_atomic_t parent_notify = NSD_REAP_CHILDREN; if (write(nsd->this_child->parent_fd, &parent_notify, sizeof(parent_notify)) == -1) { log_msg(LOG_ERR, "problems sending command from %d to parent: %s", (int) nsd->this_child->pid, strerror(errno)); } } else /* no parent, so reap 'em */ while (waitpid(-1, NULL, WNOHANG) > 0) ; nsd->mode = NSD_RUN; } else if(mode == NSD_RUN) { /* Wait for a query... */ if(event_base_loop(event_base, EVLOOP_ONCE) == -1) { if (errno != EINTR) { log_msg(LOG_ERR, "dispatch failed: %s", strerror(errno)); break; } } } else if(mode == NSD_QUIT) { /* ignore here, quit */ } else { log_msg(LOG_ERR, "mode bad value %d, back to service.", (int)mode); nsd->mode = NSD_RUN; } } #ifdef BIND8_STATS bind8_stats(nsd); #endif /* BIND8_STATS */ #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_deinit(nsd->this_child->child_num); #endif event_base_free(event_base); region_destroy(server_region); #endif server_shutdown(nsd); } #if defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) static void handle_udp(int fd, short event, void* arg) { struct udp_handler_data *data = (struct udp_handler_data *) arg; int received, sent, recvcount, i; struct query *q; if (!(event & EV_READ)) { return; } recvcount = recvmmsg(fd, msgs, NUM_RECV_PER_SELECT, 0, NULL); /* this printf strangely gave a performance increase on Linux */ /* printf("recvcount %d \n", recvcount); */ if (recvcount == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvmmsg failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } /* Simply no data available */ return; } for (i = 0; i < recvcount; i++) { loopstart: received = msgs[i].msg_len; queries[i]->addrlen = msgs[i].msg_hdr.msg_namelen; q = queries[i]; if (received == -1) { log_msg(LOG_ERR, "recvmmsg %d failed %s", i, strerror( msgs[i].msg_hdr.msg_flags)); STATUP(data->nsd, rxerr); /* No zone statup */ query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; goto swap_drop; } /* Account... */ #ifdef BIND8_STATS if (data->socket->fam == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->fam == AF_INET6) { STATUP(data->nsd, qudp6); } #endif buffer_skip(q->packet, received); buffer_flip(q->packet); #ifdef USE_DNSTAP dt_collector_submit_auth_query(data->nsd, &q->addr, q->addrlen, q->tcp, q->packet); #endif /* USE_DNSTAP */ /* Process and answer the query... */ if (server_process_query_udp(data->nsd, q) != QUERY_DISCARDED) { if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, q->zone, nona); } #ifdef USE_ZONE_STATS if (data->socket->fam == AF_INET) { ZTATUP(data->nsd, q->zone, qudp); } else if (data->socket->fam == AF_INET6) { ZTATUP(data->nsd, q->zone, qudp6); } #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); iovecs[i].iov_len = buffer_remaining(q->packet); #ifdef BIND8_STATS /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(data->nsd, q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(data->nsd, q->zone, truncated); } #endif /* BIND8_STATS */ #ifdef USE_DNSTAP dt_collector_submit_auth_response(data->nsd, &q->addr, q->addrlen, q->tcp, q->packet, q->zone); #endif /* USE_DNSTAP */ } else { query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; swap_drop: STATUP(data->nsd, dropped); ZTATUP(data->nsd, q->zone, dropped); if(i != recvcount-1) { /* swap with last and decrease recvcount */ struct mmsghdr mtmp = msgs[i]; struct iovec iotmp = iovecs[i]; recvcount--; msgs[i] = msgs[recvcount]; iovecs[i] = iovecs[recvcount]; queries[i] = queries[recvcount]; msgs[recvcount] = mtmp; iovecs[recvcount] = iotmp; queries[recvcount] = q; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[recvcount].msg_hdr.msg_iov = &iovecs[recvcount]; goto loopstart; } else { recvcount --; } } } /* send until all are sent */ i = 0; while(iaddr, a, sizeof(a)); log_msg(LOG_ERR, "sendmmsg [0]=%s count=%d failed: %s", a, (int)(recvcount-i), es); #ifdef BIND8_STATS data->nsd->st.txerr += recvcount-i; #endif /* BIND8_STATS */ break; } i += sent; } for(i=0; ipacket); msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; } } #else /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */ static void handle_udp(int fd, short event, void* arg) { struct udp_handler_data *data = (struct udp_handler_data *) arg; int received, sent; #ifndef NONBLOCKING_IS_BROKEN #ifdef HAVE_RECVMMSG int recvcount; #endif /* HAVE_RECVMMSG */ int i; #endif /* NONBLOCKING_IS_BROKEN */ struct query *q; #if (defined(NONBLOCKING_IS_BROKEN) || !defined(HAVE_RECVMMSG)) q = data->query; #endif if (!(event & EV_READ)) { return; } #ifndef NONBLOCKING_IS_BROKEN #ifdef HAVE_RECVMMSG recvcount = recvmmsg(fd, msgs, NUM_RECV_PER_SELECT, 0, NULL); /* this printf strangely gave a performance increase on Linux */ /* printf("recvcount %d \n", recvcount); */ if (recvcount == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvmmsg failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } /* Simply no data available */ return; } for (i = 0; i < recvcount; i++) { received = msgs[i].msg_len; queries[i]->addrlen = msgs[i].msg_hdr.msg_namelen; if (received == -1) { log_msg(LOG_ERR, "recvmmsg failed"); STATUP(data->nsd, rxerr); /* No zone statup */ /* the error can be found in msgs[i].msg_hdr.msg_flags */ query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; continue; } q = queries[i]; #else for(i=0; ipacket), buffer_remaining(q->packet), 0, (struct sockaddr *)&q->addr, &q->addrlen); if (received == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } return; } #endif /* NONBLOCKING_IS_BROKEN || !HAVE_RECVMMSG */ /* Account... */ if (data->socket->fam == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->fam == AF_INET6) { STATUP(data->nsd, qudp6); } buffer_skip(q->packet, received); buffer_flip(q->packet); #ifdef USE_DNSTAP dt_collector_submit_auth_query(data->nsd, &q->addr, q->addrlen, q->tcp, q->packet); #endif /* USE_DNSTAP */ /* Process and answer the query... */ if (server_process_query_udp(data->nsd, q) != QUERY_DISCARDED) { if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, q->zone, nona); } #ifdef USE_ZONE_STATS if (data->socket->fam == AF_INET) { ZTATUP(data->nsd, q->zone, qudp); } else if (data->socket->fam == AF_INET6) { ZTATUP(data->nsd, q->zone, qudp6); } #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); sent = sendto(fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *) &q->addr, q->addrlen); if (sent == -1) { const char* es = strerror(errno); char a[48]; addr2str(&q->addr, a, sizeof(a)); log_msg(LOG_ERR, "sendto %s failed: %s", a, es); STATUP(data->nsd, txerr); ZTATUP(data->nsd, q->zone, txerr); } else if ((size_t) sent != buffer_remaining(q->packet)) { log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); } else { #ifdef BIND8_STATS /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(data->nsd, q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(data->nsd, q->zone, truncated); } #endif /* BIND8_STATS */ #ifdef USE_DNSTAP dt_collector_submit_auth_response(data->nsd, &q->addr, q->addrlen, q->tcp, q->packet, q->zone); #endif /* USE_DNSTAP */ } } else { STATUP(data->nsd, dropped); ZTATUP(data->nsd, q->zone, dropped); } #ifndef NONBLOCKING_IS_BROKEN #ifdef HAVE_RECVMMSG query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; #endif } #endif } #endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */ static void cleanup_tcp_handler(struct tcp_handler_data* data) { event_del(&data->event); close(data->event.ev_fd); /* * Enable the TCP accept handlers when the current number of * TCP connections is about to drop below the maximum number * of TCP connections. */ if (slowaccept || data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) { configure_handler_event_types(EV_READ|EV_PERSIST); if(slowaccept) { event_del(&slowaccept_event); slowaccept = 0; } } --data->nsd->current_tcp_count; assert(data->nsd->current_tcp_count >= 0); region_destroy(data->region); } static void handle_tcp_reading(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t received; struct event_base* ev_base; struct timeval timeout; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(data); return; } assert((event & EV_READ)); if (data->bytes_transmitted == 0) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); } /* * Check if we received the leading packet length bytes yet. */ if (data->bytes_transmitted < sizeof(uint16_t)) { received = read(fd, (char *) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more * data is available. */ return; } else { char buf[48]; addr2str(&data->query->addr, buf, sizeof(buf)); #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); cleanup_tcp_handler(data); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(data); return; } data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(data); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(data); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ received = read(fd, buffer_current(data->query->packet), buffer_remaining(data->query->packet)); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more data is * available. */ return; } else { char buf[48]; addr2str(&data->query->addr, buf, sizeof(buf)); #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); cleanup_tcp_handler(data); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(data); return; } data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifdef BIND8_STATS #ifndef INET6 STATUP(data->nsd, ctcp); #else if (data->query->addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } #endif #endif /* BIND8_STATS */ /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); #ifdef USE_DNSTAP dt_collector_submit_auth_query(data->nsd, &data->query->addr, data->query->addrlen, data->query->tcp, data->query->packet); #endif /* USE_DNSTAP */ data->query_state = server_process_query(data->nsd, data->query); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); ZTATUP(data->nsd, data->query->zone, dropped); cleanup_tcp_handler(data); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->nsd, data->query->zone, nona); } #endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS #ifndef INET6 ZTATUP(data->nsd, data->query->zone, ctcp); #else if (data->query->addr.ss_family == AF_INET) { ZTATUP(data->nsd, data->query->zone, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { ZTATUP(data->nsd, data->query->zone, ctcp6); } #endif #endif /* USE_ZONE_STATS */ query_add_optional(data->query, data->nsd); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); #ifdef USE_DNSTAP dt_collector_submit_auth_response(data->nsd, &data->query->addr, data->query->addrlen, data->query->tcp, data->query->packet, data->query->zone); #endif /* USE_DNSTAP */ data->bytes_transmitted = 0; timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, handle_tcp_writing, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpr failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpr failed"); /* see if we can write the answer right away(usually so,EAGAIN ifnot)*/ handle_tcp_writing(fd, EV_WRITE, data); } static void handle_tcp_writing(int fd, short event, void* arg) { struct tcp_handler_data *data = (struct tcp_handler_data *) arg; ssize_t sent; struct query *q = data->query; struct timeval timeout; struct event_base* ev_base; if ((event & EV_TIMEOUT)) { /* Connection timed out. */ cleanup_tcp_handler(data); return; } assert((event & EV_WRITE)); if (data->bytes_transmitted < sizeof(q->tcplen)) { /* Writing the response packet length. */ uint16_t n_tcplen = htons(q->tcplen); #ifdef HAVE_WRITEV struct iovec iov[2]; iov[0].iov_base = (uint8_t*)&n_tcplen + data->bytes_transmitted; iov[0].iov_len = sizeof(n_tcplen) - data->bytes_transmitted; iov[1].iov_base = buffer_begin(q->packet); iov[1].iov_len = buffer_limit(q->packet); sent = writev(fd, iov, 2); #else /* HAVE_WRITEV */ sent = write(fd, (const char *) &n_tcplen + data->bytes_transmitted, sizeof(n_tcplen) - data->bytes_transmitted); #endif /* HAVE_WRITEV */ if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(data); return; } } data->bytes_transmitted += sent; if (data->bytes_transmitted < sizeof(q->tcplen)) { /* * Writing not complete, wait until socket * becomes writable again. */ return; } #ifdef HAVE_WRITEV sent -= sizeof(n_tcplen); /* handle potential 'packet done' code */ goto packet_could_be_done; #endif } sent = write(fd, buffer_current(q->packet), buffer_remaining(q->packet)); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(data); return; } } data->bytes_transmitted += sent; #ifdef HAVE_WRITEV packet_could_be_done: #endif buffer_skip(q->packet, sent); if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); data->query_state = query_axfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, handle_tcp_writing, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpw failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpw failed"); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { (void) shutdown(fd, SHUT_WR); } data->bytes_transmitted = 0; timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; ev_base = data->event.ev_base; event_del(&data->event); event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpw failed"); if(event_add(&data->event, &timeout) != 0) log_msg(LOG_ERR, "event add tcpw failed"); } static void handle_slowaccept_timeout(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) { if(slowaccept) { configure_handler_event_types(EV_PERSIST | EV_READ); slowaccept = 0; } } /* * Handle an incoming TCP connection. The connection is accepted and * a new TCP reader event handler is added. The TCP handler * is responsible for cleanup when the connection is closed. */ static void handle_tcp_accept(int fd, short event, void* arg) { struct tcp_accept_handler_data *data = (struct tcp_accept_handler_data *) arg; int s; struct tcp_handler_data *tcp_data; region_type *tcp_region; #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; struct timeval timeout; if (!(event & EV_READ)) { return; } if (data->nsd->current_tcp_count >= data->nsd->maximum_tcp_count) { return; } /* Accept it... */ addrlen = sizeof(addr); #ifndef HAVE_ACCEPT4 s = accept(fd, (struct sockaddr *) &addr, &addrlen); #else s = accept4(fd, (struct sockaddr *) &addr, &addrlen, SOCK_NONBLOCK); #endif if (s == -1) { /** * EMFILE and ENFILE is a signal that the limit of open * file descriptors has been reached. Pause accept(). * EINTR is a signal interrupt. The others are various OS ways * of saying that the client has closed the connection. */ if (errno == EMFILE || errno == ENFILE) { if (!slowaccept) { /* disable accept events */ struct timeval tv; configure_handler_event_types(0); tv.tv_sec = SLOW_ACCEPT_TIMEOUT; tv.tv_usec = 0L; event_set(&slowaccept_event, -1, EV_TIMEOUT, handle_slowaccept_timeout, NULL); (void)event_base_set(data->event.ev_base, &slowaccept_event); (void)event_add(&slowaccept_event, &tv); slowaccept = 1; /* We don't want to spam the logs here */ } } else if (errno != EINTR && errno != EWOULDBLOCK #ifdef ECONNABORTED && errno != ECONNABORTED #endif /* ECONNABORTED */ #ifdef EPROTO && errno != EPROTO #endif /* EPROTO */ ) { log_msg(LOG_ERR, "accept failed: %s", strerror(errno)); } return; } #ifndef HAVE_ACCEPT4 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); close(s); return; } #endif /* * This region is deallocated when the TCP connection is * closed by the TCP handler. */ tcp_region = region_create(xalloc, free); tcp_data = (struct tcp_handler_data *) region_alloc( tcp_region, sizeof(struct tcp_handler_data)); tcp_data->region = tcp_region; tcp_data->query = query_create(tcp_region, compressed_dname_offsets, compression_table_size, compressed_dnames); tcp_data->nsd = data->nsd; tcp_data->query_count = 0; tcp_data->query_state = QUERY_PROCESSED; tcp_data->bytes_transmitted = 0; memcpy(&tcp_data->query->addr, &addr, addrlen); tcp_data->query->addrlen = addrlen; tcp_data->tcp_timeout = data->nsd->tcp_timeout * 1000; if (data->nsd->current_tcp_count > data->nsd->maximum_tcp_count/2) { /* very busy, give smaller timeout */ tcp_data->tcp_timeout = 200; } timeout.tv_sec = tcp_data->tcp_timeout / 1000; timeout.tv_usec = (tcp_data->tcp_timeout % 1000)*1000; event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT, handle_tcp_reading, tcp_data); if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) { log_msg(LOG_ERR, "cannot set tcp event base"); close(s); region_destroy(tcp_region); return; } if(event_add(&tcp_data->event, &timeout) != 0) { log_msg(LOG_ERR, "cannot add tcp to event base"); close(s); region_destroy(tcp_region); return; } /* * Keep track of the total number of TCP handlers installed so * we can stop accepting connections when the maximum number * of simultaneous TCP connections is reached. */ ++data->nsd->current_tcp_count; if (data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) { configure_handler_event_types(0); } } static void send_children_command(struct nsd* nsd, sig_atomic_t command, int timeout) { size_t i; assert(nsd->server_kind == NSD_SERVER_MAIN && nsd->this_child == 0); for (i = 0; i < nsd->child_count; ++i) { if (nsd->children[i].pid > 0 && nsd->children[i].child_fd != -1) { if (write(nsd->children[i].child_fd, &command, sizeof(command)) == -1) { if(errno != EAGAIN && errno != EINTR) log_msg(LOG_ERR, "problems sending command %d to server %d: %s", (int) command, (int) nsd->children[i].pid, strerror(errno)); } else if (timeout > 0) { (void)block_read(NULL, nsd->children[i].child_fd, &command, sizeof(command), timeout); } fsync(nsd->children[i].child_fd); close(nsd->children[i].child_fd); nsd->children[i].child_fd = -1; } } } static void send_children_quit(struct nsd* nsd) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "send children quit")); send_children_command(nsd, NSD_QUIT, 0); } static void send_children_quit_and_wait(struct nsd* nsd) { DEBUG(DEBUG_IPC, 1, (LOG_INFO, "send children quit and wait")); send_children_command(nsd, NSD_QUIT_CHILD, 3); } #ifdef BIND8_STATS static void set_children_stats(struct nsd* nsd) { size_t i; assert(nsd->server_kind == NSD_SERVER_MAIN && nsd->this_child == 0); DEBUG(DEBUG_IPC, 1, (LOG_INFO, "parent set stats to send to children")); for (i = 0; i < nsd->child_count; ++i) { nsd->children[i].need_to_send_STATS = 1; nsd->children[i].handler->event_types |= NETIO_EVENT_WRITE; } } #endif /* BIND8_STATS */ static void configure_handler_event_types(short event_types) { size_t i; for (i = 0; i < tcp_accept_handler_count; ++i) { struct event* handler = &tcp_accept_handlers[i].event; if(event_types) { /* reassign */ int fd = handler->ev_fd; struct event_base* base = handler->ev_base; if(tcp_accept_handlers[i].event_added) event_del(handler); event_set(handler, fd, event_types, handle_tcp_accept, &tcp_accept_handlers[i]); if(event_base_set(base, handler) != 0) log_msg(LOG_ERR, "conhand: cannot event_base"); if(event_add(handler, NULL) != 0) log_msg(LOG_ERR, "conhand: cannot event_add"); tcp_accept_handlers[i].event_added = 1; } else { /* remove */ if(tcp_accept_handlers[i].event_added) { event_del(handler); tcp_accept_handlers[i].event_added = 0; } } } } nsd-4.1.26/util.h0000664000175000017500000002435713346473502013176 0ustar wouterwouter/* * util.h -- set of various support routines. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _UTIL_H_ #define _UTIL_H_ #include #include #include #include struct rr; struct buffer; struct region; #ifdef HAVE_SYSLOG_H # include #else # define LOG_ERR 3 # 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) \ (((n) + (alignment) - 1) & (~((alignment) - 1))) #define PADDING(n, alignment) \ (ALIGN_UP((n), (alignment)) - (n)) /* * Initialize the logging system. All messages are logged to stderr * until log_open and log_set_log_function are called. */ void log_init(const char *ident); /* * Open the system log. If FILENAME is not NULL, a log file is opened * as well. */ void log_open(int option, int facility, const char *filename); /* * Reopen the logfile. */ void log_reopen(const char *filename, uint8_t verbose); /* * Finalize the logging system. */ void log_finalize(void); /* * Type of function to use for the actual logging. */ typedef void log_function_type(int priority, const char *message); /* * The function used to log to the log file. */ log_function_type log_file; /* * The function used to log to syslog. The messages are also logged * using log_file. */ log_function_type log_syslog; /* * Set the logging function to use (log_file or log_syslog). */ void log_set_log_function(log_function_type *log_function); /* * Log a message using the current log function. */ void log_msg(int priority, const char *format, ...) ATTR_FORMAT(printf, 2, 3); /* * Log a message using the current log function. */ void log_vmsg(int priority, const char *format, va_list args); /* * Verbose output switch */ extern int verbosity; #define VERBOSITY(level, args) \ do { \ if ((level) <= verbosity) { \ log_msg args ; \ } \ } while (0) /* * Set the INDEXth bit of BITS to 1. */ void set_bit(uint8_t bits[], size_t index); /* * Set the INDEXth bit of BITS to 0. */ void clear_bit(uint8_t bits[], size_t index); /* * Return the value of the INDEXth bit of BITS. */ int get_bit(uint8_t bits[], size_t index); /* A general purpose lookup table */ typedef struct lookup_table lookup_table_type; struct lookup_table { int id; const char *name; }; /* * Looks up the table entry by name, returns NULL if not found. */ lookup_table_type *lookup_by_name(lookup_table_type table[], const char *name); /* * Looks up the table entry by id, returns NULL if not found. */ lookup_table_type *lookup_by_id(lookup_table_type table[], int id); /* * (Re-)allocate SIZE bytes of memory. Report an error if the memory * could not be allocated and exit the program. These functions never * return NULL. */ void *xalloc(size_t size); void *xmallocarray(size_t num, size_t size); void *xalloc_zero(size_t size); void *xalloc_array_zero(size_t num, size_t size); void *xrealloc(void *ptr, size_t size); /* * Mmap allocator routines. * */ #ifdef USE_MMAP_ALLOC void *mmap_alloc(size_t size); void mmap_free(void *ptr); #endif /* USE_MMAP_ALLOC */ /* * Write SIZE bytes of DATA to FILE. Report an error on failure. * * Returns 0 on failure, 1 on success. */ int write_data(FILE *file, const void *data, size_t size); /* * like write_data, but keeps track of crc */ int write_data_crc(FILE *file, const void *data, size_t size, uint32_t* crc); /* * Write the complete buffer to the socket, irrespective of short * writes or interrupts. This function blocks to write the data. * Returns 0 on error, 1 on success. */ int write_socket(int s, const void *data, size_t size); /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ static inline void write_uint16(void *dst, uint16_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint16_t *) dst = htons(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 8) & 0xff); p[1] = (uint8_t) (data & 0xff); #endif } static inline void write_uint32(void *dst, uint32_t data) { #ifdef ALLOW_UNALIGNED_ACCESSES * (uint32_t *) dst = htonl(data); #else uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 24) & 0xff); p[1] = (uint8_t) ((data >> 16) & 0xff); p[2] = (uint8_t) ((data >> 8) & 0xff); p[3] = (uint8_t) (data & 0xff); #endif } static inline void write_uint64(void *dst, uint64_t data) { uint8_t *p = (uint8_t *) dst; p[0] = (uint8_t) ((data >> 56) & 0xff); p[1] = (uint8_t) ((data >> 48) & 0xff); p[2] = (uint8_t) ((data >> 40) & 0xff); p[3] = (uint8_t) ((data >> 32) & 0xff); p[4] = (uint8_t) ((data >> 24) & 0xff); p[5] = (uint8_t) ((data >> 16) & 0xff); p[6] = (uint8_t) ((data >> 8) & 0xff); p[7] = (uint8_t) (data & 0xff); } /* * Copy data allowing for unaligned accesses in network byte order * (big endian). */ static inline uint16_t read_uint16(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohs(* (uint16_t *) src); #else uint8_t *p = (uint8_t *) src; return (p[0] << 8) | p[1]; #endif } static inline uint32_t read_uint32(const void *src) { #ifdef ALLOW_UNALIGNED_ACCESSES return ntohl(* (uint32_t *) src); #else uint8_t *p = (uint8_t *) src; return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; #endif } static inline uint64_t read_uint64(const void *src) { uint8_t *p = (uint8_t *) src; return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) | ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | ((uint64_t)p[6] << 8) | (uint64_t)p[7]; } /* * Print debugging information using log_msg, * set the logfile as /dev/stdout or /dev/stderr if you like. * nsd -F 0xFFFF enables all debug facilities. */ #define DEBUG_PARSER 0x0001U #define DEBUG_ZONEC 0x0002U #define DEBUG_QUERY 0x0004U #define DEBUG_DBACCESS 0x0008U #define DEBUG_NAME_COMPRESSION 0x0010U #define DEBUG_XFRD 0x0020U #define DEBUG_IPC 0x0040U extern unsigned nsd_debug_facilities; extern int nsd_debug_level; #ifdef NDEBUG #define DEBUG(facility, level, args) /* empty */ #else #define DEBUG(facility, level, args) \ do { \ if ((facility) & nsd_debug_facilities && \ (level) <= nsd_debug_level) { \ log_msg args ; \ } \ } while (0) #endif /* set to true to log time prettyprinted, or false to print epoch */ extern int log_time_asc; /* * Timespec functions. */ int timespec_compare(const struct timespec *left, const struct timespec *right); void timespec_add(struct timespec *left, const struct timespec *right); void timespec_subtract(struct timespec *left, const struct timespec *right); static inline void timeval_to_timespec(struct timespec *left, const struct timeval *right) { left->tv_sec = right->tv_sec; left->tv_nsec = 1000 * right->tv_usec; } /* get the time */ void get_time(struct timespec* t); /* * Converts a string representation of a period of time into * a long integer of seconds or serial value. * * Set the endptr to the first illegal character. * * Interface is similar as strtol(3) * * Returns: * LONG_MIN if underflow occurs * LONG_MAX if overflow occurs. * otherwise number of seconds * * XXX These functions do not check the range. * */ uint32_t strtoserial(const char *nptr, const char **endptr); uint32_t strtottl(const char *nptr, const char **endptr); /* * Convert binary data to a string of hexadecimal characters. */ ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize); /* * convert base32 data from and to string. Returns length. * -1 on error. Use (byte count*8)%5==0. */ int b32_pton(char const *src, uint8_t *target, size_t targsize); int b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); /* * Strip trailing and leading whitespace from str. */ void strip_string(char *str); /* * Convert a single (hexadecimal) digit to its integer value. */ int hexdigit_to_int(char ch); /* * Convert TM to seconds since epoch (midnight, January 1st, 1970). * Like timegm(3), which is not always available. */ time_t mktime_from_utc(const struct tm *tm); /* * Add bytes to given crc. Returns new CRC sum. * Start crc val with 0xffffffff on first call. XOR crc with * 0xffffffff at the end again to get final POSIX 1003.2 checksum. */ uint32_t compute_crc(uint32_t crc, uint8_t* data, size_t len); /* * Compares two 32-bit serial numbers as defined in RFC1982. Returns * <0 if a < b, 0 if a == b, and >0 if a > b. The result is undefined * if a != b but neither is greater or smaller (see RFC1982 section * 3.2.). */ int compare_serial(uint32_t a, uint32_t b); /* * Generate a random query ID. */ uint16_t qid_generate(void); /* value between 0 .. (max-1) inclusive */ int random_generate(int max); /* * call region_destroy on (region*)data, useful for region_add_cleanup(). */ void cleanup_region(void *data); /* * Region used to store owner and origin of previous RR (used * for pretty printing of zone data). * Keep the same between calls to print_rr. */ struct state_pretty_rr { struct region *previous_owner_region; const struct dname *previous_owner; const struct dname *previous_owner_origin; }; struct state_pretty_rr* create_pretty_rr(struct region* region); /* print rr to file, returns 0 on failure(nothing is written) */ int print_rr(FILE *out, struct state_pretty_rr* state, struct rr *record, struct region* tmp_region, struct buffer* tmp_buffer); /* * Convert a numeric rcode value to a human readable string */ const char* rcode2str(int rc); void addr2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len); /** copy dirname string and append slash. Previous dirname is leaked, * but it is to be used once, at startup, for chroot */ void append_trailing_slash(const char** dirname, struct region* region); /** true if filename starts with chroot or is not absolute */ int file_inside_chroot(const char* fname, const char* chr); /** Something went wrong, give error messages and exit. */ void error(const char *format, ...) ATTR_FORMAT(printf, 1, 2) ATTR_NORETURN; #endif /* _UTIL_H_ */ nsd-4.1.26/xfrd-disk.h0000664000175000017500000000177113003650075014077 0ustar wouterwouter/* * xfrd-disk.h - XFR (transfer) Daemon TCP system header file. Save/Load state to disk. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_DISK_H #define XFRD_DISK_H struct xfrd_state; struct nsd; /* magic string to identify xfrd state file */ #define XFRD_FILE_MAGIC "NSDXFRD2" /* read from state file as many zones as possible (until error/eof).*/ void xfrd_read_state(struct xfrd_state* xfrd); /* write xfrd zone state if possible */ void xfrd_write_state(struct xfrd_state* xfrd); /* create temp directory */ void xfrd_make_tempdir(struct nsd* nsd); /* rmdir temp directory */ void xfrd_del_tempdir(struct nsd* nsd); /* open temp file, makes directory if needed */ FILE* xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode); /* unlink temp file */ void xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number); /* get temp file size */ uint64_t xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ); #endif /* XFRD_DISK_H */ nsd-4.1.26/configparser.y0000664000175000017500000010062113355422740014707 0ustar wouterwouter/* * configparser.y -- yacc grammar for NSD configuration files * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ %{ #include "config.h" #include #include #include #include #include #include "options.h" #include "util.h" #include "dname.h" #include "tsig.h" #include "rrl.h" #include "configyyrename.h" int c_lex(void); void c_error(const char *message); #ifdef __cplusplus extern "C" #endif /* __cplusplus */ /* these need to be global, otherwise they cannot be used inside yacc */ extern config_parser_state_type* cfg_parser; #if 0 #define OUTYY(s) printf s /* used ONLY when debugging */ #else #define OUTYY(s) #endif %} %union { char* str; } %token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR %token STRING %token VAR_SERVER VAR_NAME VAR_IP_ADDRESS VAR_IP_TRANSPARENT VAR_DEBUG_MODE %token VAR_IP4_ONLY VAR_IP6_ONLY VAR_DATABASE VAR_IDENTITY VAR_NSID VAR_LOGFILE %token VAR_SERVER_COUNT VAR_TCP_COUNT VAR_PIDFILE VAR_PORT VAR_STATISTICS %token VAR_CHROOT VAR_USERNAME VAR_ZONESDIR VAR_XFRDFILE VAR_DIFFFILE %token VAR_XFRD_RELOAD_TIMEOUT VAR_TCP_QUERY_COUNT VAR_TCP_TIMEOUT %token VAR_IPV4_EDNS_SIZE VAR_IPV6_EDNS_SIZE VAR_DO_IP4 VAR_DO_IP6 %token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_IP_FREEBIND %token VAR_ZONEFILE %token VAR_ZONE %token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR VAR_SIZE_LIMIT_XFR %token VAR_NOTIFY_RETRY VAR_OUTGOING_INTERFACE VAR_ALLOW_AXFR_FALLBACK %token VAR_KEY %token VAR_ALGORITHM VAR_SECRET %token VAR_AXFR VAR_UDP %token VAR_VERBOSITY VAR_HIDE_VERSION %token VAR_PATTERN VAR_INCLUDEPATTERN VAR_ZONELISTFILE %token VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE VAR_CONTROL_INTERFACE %token VAR_CONTROL_PORT VAR_SERVER_KEY_FILE VAR_SERVER_CERT_FILE %token VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE VAR_XFRDIR %token VAR_RRL_SIZE VAR_RRL_RATELIMIT VAR_RRL_SLIP %token VAR_RRL_IPV4_PREFIX_LENGTH VAR_RRL_IPV6_PREFIX_LENGTH %token VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST %token VAR_ZONEFILES_CHECK VAR_ZONEFILES_WRITE VAR_LOG_TIME_ASCII %token VAR_ROUND_ROBIN VAR_ZONESTATS VAR_REUSEPORT VAR_VERSION %token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME %token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME %token VAR_MULTI_MASTER_CHECK VAR_MINIMAL_RESPONSES VAR_REFUSE_ANY %token VAR_USE_SYSTEMD VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH %token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION VAR_DNSTAP_IDENTITY %token VAR_DNSTAP_VERSION VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvar: serverstart contents_server | zonestart contents_zone | keystart contents_key | patternstart contents_pattern | rcstart contents_rc | dtstart contents_dt; /* server: declaration */ serverstart: VAR_SERVER { OUTYY(("\nP(server:)\n")); if(cfg_parser->server_settings_seen) { yyerror("duplicate server: element."); } cfg_parser->server_settings_seen = 1; } ; contents_server: contents_server content_server | ; content_server: server_ip_address | server_ip_transparent | server_debug_mode | server_ip4_only | server_ip6_only | server_database | server_identity | server_nsid | server_logfile | server_server_count | server_tcp_count | server_pidfile | server_port | server_statistics | server_chroot | server_username | server_zonesdir | server_difffile | server_xfrdfile | server_xfrd_reload_timeout | server_tcp_query_count | server_tcp_timeout | server_ipv4_edns_size | server_ipv6_edns_size | server_verbosity | server_hide_version | server_zonelistfile | server_xfrdir | server_tcp_mss | server_outgoing_tcp_mss | server_rrl_size | server_rrl_ratelimit | server_rrl_slip | server_rrl_ipv4_prefix_length | server_rrl_ipv6_prefix_length | server_rrl_whitelist_ratelimit | server_zonefiles_check | server_do_ip4 | server_do_ip6 | server_zonefiles_write | server_log_time_ascii | server_round_robin | server_reuseport | server_version | server_ip_freebind | server_minimal_responses | server_refuse_any | server_use_systemd; server_ip_address: VAR_IP_ADDRESS STRING { OUTYY(("P(server_ip_address:%s)\n", $2)); if(cfg_parser->current_ip_address_option) { cfg_parser->current_ip_address_option->next = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); cfg_parser->current_ip_address_option = cfg_parser->current_ip_address_option->next; cfg_parser->current_ip_address_option->next=0; } else { cfg_parser->current_ip_address_option = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); cfg_parser->current_ip_address_option->next=0; cfg_parser->opt->ip_addresses = cfg_parser->current_ip_address_option; } cfg_parser->current_ip_address_option->address = region_strdup(cfg_parser->opt->region, $2); } ; server_ip_transparent: VAR_IP_TRANSPARENT STRING { OUTYY(("P(server_ip_transparent:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->ip_transparent = (strcmp($2, "yes")==0); } ; server_ip_freebind: VAR_IP_FREEBIND STRING { OUTYY(("P(server_ip_freebind:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->ip_freebind = (strcmp($2, "yes")==0); } ; server_debug_mode: VAR_DEBUG_MODE STRING { OUTYY(("P(server_debug_mode:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->debug_mode = (strcmp($2, "yes")==0); } ; server_use_systemd: VAR_USE_SYSTEMD STRING { OUTYY(("P(server_use_systemd:%s)\n", $2)); } ; server_verbosity: VAR_VERBOSITY STRING { OUTYY(("P(server_verbosity:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else cfg_parser->opt->verbosity = atoi($2); } ; server_hide_version: VAR_HIDE_VERSION STRING { OUTYY(("P(server_hide_version:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->hide_version = (strcmp($2, "yes")==0); } ; server_ip4_only: VAR_IP4_ONLY STRING { /* for backwards compatibility in config file with NSD3 */ OUTYY(("P(server_ip4_only:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else if(strcmp($2, "yes")==0) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } } ; server_ip6_only: VAR_IP6_ONLY STRING { /* for backwards compatibility in config file with NSD3 */ OUTYY(("P(server_ip6_only:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else if(strcmp($2, "yes")==0) { cfg_parser->opt->do_ip6 = 1; cfg_parser->opt->do_ip4 = 0; } } ; server_do_ip4: VAR_DO_IP4 STRING { OUTYY(("P(server_do_ip4:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->do_ip4 = (strcmp($2, "yes")==0); } ; server_do_ip6: VAR_DO_IP6 STRING { OUTYY(("P(server_do_ip6:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->do_ip6 = (strcmp($2, "yes")==0); } ; server_reuseport: VAR_REUSEPORT STRING { OUTYY(("P(server_reuseport:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->reuseport = (strcmp($2, "yes")==0); } ; server_database: VAR_DATABASE STRING { OUTYY(("P(server_database:%s)\n", $2)); cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2); if(cfg_parser->opt->database[0] == 0 && cfg_parser->opt->zonefiles_write == 0) cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; } ; server_identity: VAR_IDENTITY STRING { OUTYY(("P(server_identity:%s)\n", $2)); cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); } ; server_version: VAR_VERSION STRING { OUTYY(("P(server_version:%s)\n", $2)); cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); } ; server_nsid: VAR_NSID STRING { unsigned char* nsid = 0; size_t nsid_len = 0; OUTYY(("P(server_nsid:%s)\n", $2)); if (strncasecmp($2, "ascii_", 6) == 0) { nsid_len = strlen($2+6); if(nsid_len < 65535) { cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); } else yyerror("NSID too long"); } else if (strlen($2) % 2 != 0) { yyerror("the NSID must be a hex string of an even length."); } else { nsid_len = strlen($2) / 2; if(nsid_len < 65535) { nsid = xalloc(nsid_len); if (hex_pton($2, nsid, nsid_len) == -1) yyerror("hex string cannot be parsed in NSID."); else cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2); free(nsid); } else yyerror("NSID too long"); } } ; server_logfile: VAR_LOGFILE STRING { OUTYY(("P(server_logfile:%s)\n", $2)); cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); } ; server_log_time_ascii: VAR_LOG_TIME_ASCII STRING { OUTYY(("P(server_log_time_ascii:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->log_time_ascii = (strcmp($2, "yes")==0); log_time_asc = cfg_parser->opt->log_time_ascii; } } ; server_round_robin: VAR_ROUND_ROBIN STRING { OUTYY(("P(server_round_robin:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->round_robin = (strcmp($2, "yes")==0); round_robin = cfg_parser->opt->round_robin; } } ; server_minimal_responses: VAR_MINIMAL_RESPONSES STRING { OUTYY(("P(server_minimal_responses:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->minimal_responses = (strcmp($2, "yes")==0); minimal_responses = cfg_parser->opt->minimal_responses; } } ; server_refuse_any: VAR_REFUSE_ANY STRING { OUTYY(("P(server_refuse_any:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->refuse_any = (strcmp($2, "yes")==0); } } ; server_server_count: VAR_SERVER_COUNT STRING { OUTYY(("P(server_server_count:%s)\n", $2)); if(atoi($2) <= 0) yyerror("number greater than zero expected"); else cfg_parser->opt->server_count = atoi($2); } ; server_tcp_count: VAR_TCP_COUNT STRING { OUTYY(("P(server_tcp_count:%s)\n", $2)); if(atoi($2) <= 0) yyerror("number greater than zero expected"); else cfg_parser->opt->tcp_count = atoi($2); } ; server_pidfile: VAR_PIDFILE STRING { OUTYY(("P(server_pidfile:%s)\n", $2)); cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); } ; server_port: VAR_PORT STRING { OUTYY(("P(server_port:%s)\n", $2)); cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, $2); } ; server_statistics: VAR_STATISTICS STRING { OUTYY(("P(server_statistics:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else cfg_parser->opt->statistics = atoi($2); } ; server_chroot: VAR_CHROOT STRING { OUTYY(("P(server_chroot:%s)\n", $2)); cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); } ; server_username: VAR_USERNAME STRING { OUTYY(("P(server_username:%s)\n", $2)); cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); } ; server_zonesdir: VAR_ZONESDIR STRING { OUTYY(("P(server_zonesdir:%s)\n", $2)); cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); } ; server_zonelistfile: VAR_ZONELISTFILE STRING { OUTYY(("P(server_zonelistfile:%s)\n", $2)); cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); } ; server_xfrdir: VAR_XFRDIR STRING { OUTYY(("P(server_xfrdir:%s)\n", $2)); cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); } ; server_difffile: VAR_DIFFFILE STRING { OUTYY(("P(server_difffile:%s)\n", $2)); /* ignore the value for backwards compatibility in config file*/ } ; server_xfrdfile: VAR_XFRDFILE STRING { OUTYY(("P(server_xfrdfile:%s)\n", $2)); cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); } ; server_xfrd_reload_timeout: VAR_XFRD_RELOAD_TIMEOUT STRING { OUTYY(("P(server_xfrd_reload_timeout:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->xfrd_reload_timeout = atoi($2); } ; server_tcp_query_count: VAR_TCP_QUERY_COUNT STRING { OUTYY(("P(server_tcp_query_count:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_query_count = atoi($2); } ; server_tcp_timeout: VAR_TCP_TIMEOUT STRING { OUTYY(("P(server_tcp_timeout:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_timeout = atoi($2); } ; server_tcp_mss: VAR_TCP_MSS STRING { OUTYY(("P(server_tcp_mss:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_mss = atoi($2); } ; server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING { OUTYY(("P(server_outgoing_tcp_mss:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->outgoing_tcp_mss = atoi($2); } ; server_ipv4_edns_size: VAR_IPV4_EDNS_SIZE STRING { OUTYY(("P(server_ipv4_edns_size:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->ipv4_edns_size = atoi($2); } ; server_ipv6_edns_size: VAR_IPV6_EDNS_SIZE STRING { OUTYY(("P(server_ipv6_edns_size:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); cfg_parser->opt->ipv6_edns_size = atoi($2); } ; server_rrl_size: VAR_RRL_SIZE STRING { OUTYY(("P(server_rrl_size:%s)\n", $2)); #ifdef RATELIMIT if(atoi($2) <= 0) yyerror("number greater than zero expected"); cfg_parser->opt->rrl_size = atoi($2); #endif } ; server_rrl_ratelimit: VAR_RRL_RATELIMIT STRING { OUTYY(("P(server_rrl_ratelimit:%s)\n", $2)); #ifdef RATELIMIT cfg_parser->opt->rrl_ratelimit = atoi($2); #endif } ; server_rrl_slip: VAR_RRL_SLIP STRING { OUTYY(("P(server_rrl_slip:%s)\n", $2)); #ifdef RATELIMIT if(atoi($2) < 0) yyerror("number equal or greater than zero expected"); cfg_parser->opt->rrl_slip = atoi($2); #endif } ; server_rrl_ipv4_prefix_length: VAR_RRL_IPV4_PREFIX_LENGTH STRING { OUTYY(("P(server_rrl_ipv4_prefix_length:%s)\n", $2)); #ifdef RATELIMIT if(atoi($2) < 0 || atoi($2) > 32) yyerror("invalid IPv4 prefix length"); cfg_parser->opt->rrl_ipv4_prefix_length = atoi($2); #endif } ; server_rrl_ipv6_prefix_length: VAR_RRL_IPV6_PREFIX_LENGTH STRING { OUTYY(("P(server_rrl_ipv6_prefix_length:%s)\n", $2)); #ifdef RATELIMIT if(atoi($2) < 0 || atoi($2) > 64) yyerror("invalid IPv6 prefix length"); cfg_parser->opt->rrl_ipv6_prefix_length = atoi($2); #endif } ; server_rrl_whitelist_ratelimit: VAR_RRL_WHITELIST_RATELIMIT STRING { OUTYY(("P(server_rrl_whitelist_ratelimit:%s)\n", $2)); #ifdef RATELIMIT cfg_parser->opt->rrl_whitelist_ratelimit = atoi($2); #endif } ; server_zonefiles_check: VAR_ZONEFILES_CHECK STRING { OUTYY(("P(server_zonefiles_check:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->zonefiles_check = (strcmp($2, "yes")==0); } ; server_zonefiles_write: VAR_ZONEFILES_WRITE STRING { OUTYY(("P(server_zonefiles_write:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else cfg_parser->opt->zonefiles_write = atoi($2); } ; rcstart: VAR_REMOTE_CONTROL { OUTYY(("\nP(remote-control:)\n")); } ; contents_rc: contents_rc content_rc | ; content_rc: rc_control_enable | rc_control_interface | rc_control_port | rc_server_key_file | rc_server_cert_file | rc_control_key_file | rc_control_cert_file ; rc_control_enable: VAR_CONTROL_ENABLE STRING { OUTYY(("P(control_enable:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->control_enable = (strcmp($2, "yes")==0); } ; rc_control_port: VAR_CONTROL_PORT STRING { OUTYY(("P(control_port:%s)\n", $2)); if(atoi($2) == 0) yyerror("control port number expected"); else cfg_parser->opt->control_port = atoi($2); } ; rc_control_interface: VAR_CONTROL_INTERFACE STRING { ip_address_option_type* last = NULL; ip_address_option_type* o = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); OUTYY(("P(control_interface:%s)\n", $2)); /* append at end */ last = cfg_parser->opt->control_interface; while(last && last->next) last = last->next; if(last == NULL) cfg_parser->opt->control_interface = o; else last->next = o; o->next = NULL; o->address = region_strdup(cfg_parser->opt->region, $2); } ; rc_server_key_file: VAR_SERVER_KEY_FILE STRING { OUTYY(("P(rc_server_key_file:%s)\n", $2)); cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); } ; rc_server_cert_file: VAR_SERVER_CERT_FILE STRING { OUTYY(("P(rc_server_cert_file:%s)\n", $2)); cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); } ; rc_control_key_file: VAR_CONTROL_KEY_FILE STRING { OUTYY(("P(rc_control_key_file:%s)\n", $2)); cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); } ; rc_control_cert_file: VAR_CONTROL_CERT_FILE STRING { OUTYY(("P(rc_control_cert_file:%s)\n", $2)); cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); } ; /* dnstap: declaration */ dtstart: VAR_DNSTAP { OUTYY(("\nP(dnstap:)\n")); } ; contents_dt: contents_dt content_dt | ; content_dt: dt_dnstap_enable | dt_dnstap_socket_path | dt_dnstap_send_identity | dt_dnstap_send_version | dt_dnstap_identity | dt_dnstap_version | dt_dnstap_log_auth_query_messages | dt_dnstap_log_auth_response_messages ; dt_dnstap_enable: VAR_DNSTAP_ENABLE STRING { OUTYY(("P(dt_dnstap_enable:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_enable = (strcmp($2, "yes")==0); } ; dt_dnstap_socket_path: VAR_DNSTAP_SOCKET_PATH STRING { OUTYY(("P(dt_dnstap_socket_path:%s)\n", $2)); cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); } ; dt_dnstap_send_identity: VAR_DNSTAP_SEND_IDENTITY STRING { OUTYY(("P(dt_dnstap_send_identity:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_send_identity = (strcmp($2, "yes")==0); } ; dt_dnstap_send_version: VAR_DNSTAP_SEND_VERSION STRING { OUTYY(("P(dt_dnstap_send_version:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_send_version = (strcmp($2, "yes")==0); } ; dt_dnstap_identity: VAR_DNSTAP_IDENTITY STRING { OUTYY(("P(dt_dnstap_identity:%s)\n", $2)); cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); } ; dt_dnstap_version: VAR_DNSTAP_VERSION STRING { OUTYY(("P(dt_dnstap_version:%s)\n", $2)); cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); } ; dt_dnstap_log_auth_query_messages: VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES STRING { OUTYY(("P(dt_dnstap_log_auth_query_messages:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_log_auth_query_messages = (strcmp($2, "yes")==0); } ; dt_dnstap_log_auth_response_messages: VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES STRING { OUTYY(("P(dt_dnstap_log_auth_response_messages:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_log_auth_response_messages = (strcmp($2, "yes")==0); } ; /* pattern: declaration */ patternstart: VAR_PATTERN { OUTYY(("\nP(pattern:)\n")); if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("previous zone has no name"); else { if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->current_zone)) c_error("duplicate zone"); } if(!cfg_parser->current_zone->pattern) c_error("previous zone has no pattern"); cfg_parser->current_zone = NULL; } if(cfg_parser->current_pattern) { if(!cfg_parser->current_pattern->pname) c_error("previous pattern has no name"); else { if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->current_pattern)) c_error_msg("duplicate pattern %s", cfg_parser->current_pattern->pname); } } cfg_parser->current_pattern = pattern_options_create( cfg_parser->opt->region); cfg_parser->current_allow_notify = 0; cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; cfg_parser->current_outgoing_interface = 0; } ; contents_pattern: contents_pattern content_pattern | content_pattern; content_pattern: pattern_name | zone_config_item; zone_config_item: zone_zonefile | zone_allow_notify | zone_request_xfr | zone_notify | zone_notify_retry | zone_provide_xfr | zone_outgoing_interface | zone_allow_axfr_fallback | include_pattern | zone_rrl_whitelist | zone_zonestats | zone_max_refresh_time | zone_min_refresh_time | zone_max_retry_time | zone_min_retry_time | zone_size_limit_xfr | zone_multi_master_check; pattern_name: VAR_NAME STRING { OUTYY(("P(pattern_name:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif if(strchr($2, ' ')) c_error_msg("space is not allowed in pattern name: " "'%s'", $2); cfg_parser->current_pattern->pname = region_strdup(cfg_parser->opt->region, $2); } ; include_pattern: VAR_INCLUDEPATTERN STRING { OUTYY(("P(include-pattern:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif config_apply_pattern($2); } ; /* zone: declaration */ zonestart: VAR_ZONE { OUTYY(("\nP(zone:)\n")); if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("previous zone has no name"); else { if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->current_zone)) c_error("duplicate zone"); } if(!cfg_parser->current_zone->pattern) c_error("previous zone has no pattern"); } if(cfg_parser->current_pattern) { if(!cfg_parser->current_pattern->pname) c_error("previous pattern has no name"); else { if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->current_pattern)) c_error_msg("duplicate pattern %s", cfg_parser->current_pattern->pname); } } cfg_parser->current_zone = zone_options_create(cfg_parser->opt->region); cfg_parser->current_zone->part_of_config = 1; cfg_parser->current_pattern = pattern_options_create( cfg_parser->opt->region); cfg_parser->current_pattern->implicit = 1; cfg_parser->current_zone->pattern = cfg_parser->current_pattern; cfg_parser->current_allow_notify = 0; cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; cfg_parser->current_outgoing_interface = 0; } ; contents_zone: contents_zone content_zone | content_zone; content_zone: zone_name | zone_config_item; zone_name: VAR_NAME STRING { char* s; OUTYY(("P(zone_name:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_zone); assert(cfg_parser->current_pattern); #endif cfg_parser->current_zone->name = region_strdup(cfg_parser->opt->region, $2); s = (char*)region_alloc(cfg_parser->opt->region, strlen($2)+strlen(PATTERN_IMPLICIT_MARKER)+1); memmove(s, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)); memmove(s+strlen(PATTERN_IMPLICIT_MARKER), $2, strlen($2)+1); if(pattern_options_find(cfg_parser->opt, s)) c_error_msg("zone %s cannot be created because " "implicit pattern %s already exists", $2, s); cfg_parser->current_pattern->pname = s; } ; zone_zonefile: VAR_ZONEFILE STRING { OUTYY(("P(zonefile:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif cfg_parser->current_pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); } ; zone_zonestats: VAR_ZONESTATS STRING { OUTYY(("P(zonestats:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif cfg_parser->current_pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); } ; zone_allow_notify: VAR_ALLOW_NOTIFY STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); OUTYY(("P(allow_notify:%s %s)\n", $2, $3)); if(cfg_parser->current_allow_notify) cfg_parser->current_allow_notify->next = acl; else cfg_parser->current_pattern->allow_notify = acl; cfg_parser->current_allow_notify = acl; } ; zone_request_xfr: VAR_REQUEST_XFR zone_request_xfr_data { } ; zone_size_limit_xfr: VAR_SIZE_LIMIT_XFR STRING { OUTYY(("P(size_limit_xfr:%s)\n", $2)); if(atoll($2) < 0) yyerror("number >= 0 expected"); else cfg_parser->current_pattern->size_limit_xfr = atoll($2); } ; zone_request_xfr_data: STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $1, $2); OUTYY(("P(request_xfr:%s %s)\n", $1, $2)); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } | VAR_AXFR STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); acl->use_axfr_only = 1; OUTYY(("P(request_xfr:%s %s)\n", $2, $3)); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } | VAR_UDP STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); acl->allow_udp = 1; OUTYY(("P(request_xfr:%s %s)\n", $2, $3)); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } ; zone_notify: VAR_NOTIFY STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); OUTYY(("P(notify:%s %s)\n", $2, $3)); if(acl->blocked) c_error("blocked address used for notify"); if(acl->rangetype!=acl_range_single) c_error("address range used for notify"); if(cfg_parser->current_notify) cfg_parser->current_notify->next = acl; else cfg_parser->current_pattern->notify = acl; cfg_parser->current_notify = acl; } ; zone_notify_retry: VAR_NOTIFY_RETRY STRING { OUTYY(("P(notify_retry:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->notify_retry = atoi($2); cfg_parser->current_pattern->notify_retry_is_default=0; } } ; zone_provide_xfr: VAR_PROVIDE_XFR STRING STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, $3); OUTYY(("P(provide_xfr:%s %s)\n", $2, $3)); if(cfg_parser->current_provide_xfr) cfg_parser->current_provide_xfr->next = acl; else cfg_parser->current_pattern->provide_xfr = acl; cfg_parser->current_provide_xfr = acl; } ; zone_outgoing_interface: VAR_OUTGOING_INTERFACE STRING { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY"); OUTYY(("P(outgoing_interface:%s)\n", $2)); if(acl->rangetype!=acl_range_single) c_error("address range used for outgoing interface"); if(cfg_parser->current_outgoing_interface) cfg_parser->current_outgoing_interface->next = acl; else cfg_parser->current_pattern->outgoing_interface = acl; cfg_parser->current_outgoing_interface = acl; } ; zone_allow_axfr_fallback: VAR_ALLOW_AXFR_FALLBACK STRING { OUTYY(("P(allow_axfr_fallback:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else { cfg_parser->current_pattern->allow_axfr_fallback = (strcmp($2, "yes")==0); cfg_parser->current_pattern->allow_axfr_fallback_is_default = 0; } } ; zone_rrl_whitelist: VAR_RRL_WHITELIST STRING { OUTYY(("P(zone_rrl_whitelist:%s)\n", $2)); #ifdef RATELIMIT cfg_parser->current_pattern->rrl_whitelist |= rrlstr2type($2); #endif } ; zone_max_refresh_time: VAR_MAX_REFRESH_TIME STRING { OUTYY(("P(zone_max_refresh_time:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->max_refresh_time = atoi($2); cfg_parser->current_pattern->max_refresh_time_is_default = 0; } }; zone_min_refresh_time: VAR_MIN_REFRESH_TIME STRING { OUTYY(("P(zone_min_refresh_time:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->min_refresh_time = atoi($2); cfg_parser->current_pattern->min_refresh_time_is_default = 0; } }; zone_max_retry_time: VAR_MAX_RETRY_TIME STRING { OUTYY(("P(zone_max_retry_time:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->max_retry_time = atoi($2); cfg_parser->current_pattern->max_retry_time_is_default = 0; } }; zone_min_retry_time: VAR_MIN_RETRY_TIME STRING { OUTYY(("P(zone_min_retry_time:%s)\n", $2)); if(atoi($2) == 0 && strcmp($2, "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->min_retry_time = atoi($2); cfg_parser->current_pattern->min_retry_time_is_default = 0; } }; zone_multi_master_check: VAR_MULTI_MASTER_CHECK STRING { OUTYY(("P(zone_multi_master_check:%s)\n", $2)); if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->current_pattern->multi_master_check = (strcmp($2, "yes")==0); } /* key: declaration */ keystart: VAR_KEY { OUTYY(("\nP(key:)\n")); if(cfg_parser->current_key) { if(!cfg_parser->current_key->name) c_error("previous key has no name"); if(!cfg_parser->current_key->algorithm) c_error("previous key has no algorithm"); if(!cfg_parser->current_key->secret) c_error("previous key has no secret blob"); key_options_insert(cfg_parser->opt, cfg_parser->current_key); } cfg_parser->current_key = key_options_create(cfg_parser->opt->region); cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, "sha256"); } ; contents_key: contents_key content_key | content_key; content_key: key_name | key_algorithm | key_secret; key_name: VAR_NAME STRING { const dname_type* d; OUTYY(("P(key_name:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_key); #endif cfg_parser->current_key->name = region_strdup(cfg_parser->opt->region, $2); d = dname_parse(cfg_parser->opt->region, $2); if(!d) c_error_msg("Failed to parse tsig key name %s", $2); else region_recycle(cfg_parser->opt->region, (void*)d, dname_total_size(d)); } ; key_algorithm: VAR_ALGORITHM STRING { OUTYY(("P(key_algorithm:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_key); #endif if(cfg_parser->current_key->algorithm) region_recycle(cfg_parser->opt->region, cfg_parser->current_key->algorithm, strlen(cfg_parser->current_key->algorithm)+1); cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, $2); if(tsig_get_algorithm_by_name($2) == NULL) c_error_msg("Bad tsig algorithm %s", $2); } ; key_secret: VAR_SECRET STRING { uint8_t data[16384]; int size; OUTYY(("key_secret:%s)\n", $2)); #ifndef NDEBUG assert(cfg_parser->current_key); #endif cfg_parser->current_key->secret = region_strdup(cfg_parser->opt->region, $2); size = b64_pton($2, data, sizeof(data)); if(size == -1) { c_error_msg("Cannot base64 decode tsig secret %s", cfg_parser->current_key->name? cfg_parser->current_key->name:""); } else if(size != 0) { memset(data, 0xdd, size); /* wipe secret */ } } ; %% /* parse helper routines could be here */ nsd-4.1.26/rbtree.c0000664000175000017500000003271613040156013013457 0ustar wouterwouter/* * rbtree.c -- generic red black tree * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "rbtree.h" #define BLACK 0 #define RED 1 rbnode_type rbtree_null_node = { RBTREE_NULL, /* Parent. */ RBTREE_NULL, /* Left. */ RBTREE_NULL, /* Right. */ NULL, /* Key. */ BLACK /* Color. */ }; static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node); static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node); static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node); static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent); /* * Creates a new red black tree, initializes and returns a pointer to it. * * Return NULL on failure. * */ rbtree_type * rbtree_create (region_type *region, int (*cmpf)(const void *, const void *)) { rbtree_type *rbtree; /* Allocate memory for it */ rbtree = (rbtree_type *) region_alloc(region, sizeof(rbtree_type)); if (!rbtree) { return NULL; } /* Initialize it */ rbtree->root = RBTREE_NULL; rbtree->count = 0; rbtree->region = region; rbtree->cmp = cmpf; return rbtree; } /* * Rotates the node to the left. * */ static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *right = node->right; node->right = right->left; if (right->left != RBTREE_NULL) right->left->parent = node; right->parent = node->parent; if (node->parent != RBTREE_NULL) { if (node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } } else { rbtree->root = right; } right->left = node; node->parent = right; } /* * Rotates the node to the right. * */ static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *left = node->left; node->left = left->right; if (left->right != RBTREE_NULL) left->right->parent = node; left->parent = node->parent; if (node->parent != RBTREE_NULL) { if (node == node->parent->right) { node->parent->right = left; } else { node->parent->left = left; } } else { rbtree->root = left; } left->right = node; node->parent = left; } static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node) { rbnode_type *uncle; /* While not at the root and need fixing... */ while (node != rbtree->root && node->parent->color == RED) { /* If our parent is left child of our grandparent... */ if (node->parent == node->parent->parent->left) { uncle = node->parent->parent->right; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->right) { node = node->parent; rbtree_rotate_left(rbtree, node); } /* Now we're the left child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; rbtree_rotate_right(rbtree, node->parent->parent); } } else { uncle = node->parent->parent->left; /* If our uncle is red... */ if (uncle->color == RED) { /* Paint the parent and the uncle black... */ node->parent->color = BLACK; uncle->color = BLACK; /* And the grandparent red... */ node->parent->parent->color = RED; /* And continue fixing the grandparent */ node = node->parent->parent; } else { /* Our uncle is black... */ /* Are we the right child? */ if (node == node->parent->left) { node = node->parent; rbtree_rotate_right(rbtree, node); } /* Now we're the right child, repaint and rotate... */ node->parent->color = BLACK; node->parent->parent->color = RED; rbtree_rotate_left(rbtree, node->parent->parent); } } } rbtree->root->color = BLACK; } /* * Inserts a node into a red black tree. * * Returns NULL on failure or the pointer to the newly added node * otherwise. */ rbnode_type * rbtree_insert (rbtree_type *rbtree, rbnode_type *data) { /* XXX Not necessary, but keeps compiler quiet... */ int r = 0; /* We start at the root of the tree */ rbnode_type *node = rbtree->root; rbnode_type *parent = RBTREE_NULL; /* Lets find the new parent... */ while (node != RBTREE_NULL) { /* Compare two keys, do we have a duplicate? */ if ((r = rbtree->cmp(data->key, node->key)) == 0) { return NULL; } parent = node; if (r < 0) { node = node->left; } else { node = node->right; } } /* Initialize the new node */ data->parent = parent; data->left = data->right = RBTREE_NULL; data->color = RED; rbtree->count++; /* Insert it into the tree... */ if (parent != RBTREE_NULL) { if (r < 0) { parent->left = data; } else { parent->right = data; } } else { rbtree->root = data; } /* Fix up the red-black properties... */ rbtree_insert_fixup(rbtree, data); return data; } /* * Searches the red black tree, returns the data if key is found or NULL otherwise. * */ rbnode_type * rbtree_search (rbtree_type *rbtree, const void *key) { rbnode_type *node; if (rbtree_find_less_equal(rbtree, key, &node)) { return node; } else { return NULL; } } /* helpers for delete */ static void swap_int8(uint8_t* x, uint8_t* y) { uint8_t t = *x; *x = *y; *y = t; } static void swap_np(rbnode_type** x, rbnode_type** y) { rbnode_type* t = *x; *x = *y; *y = t; } static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent, rbnode_type* old, rbnode_type* new) { if(parent == RBTREE_NULL) { assert(rbtree->root == old); if(rbtree->root == old) rbtree->root = new; return; } assert(parent->left == old || parent->right == old || parent->left == new || parent->right == new); if(parent->left == old) parent->left = new; if(parent->right == old) parent->right = new; } static void change_child_ptr(rbnode_type* child, rbnode_type* old, rbnode_type* new) { if(child == RBTREE_NULL) return; assert(child->parent == old || child->parent == new); if(child->parent == old) child->parent = new; } rbnode_type* rbtree_delete(rbtree_type *rbtree, const void *key) { rbnode_type *to_delete; rbnode_type *child; if((to_delete = rbtree_search(rbtree, key)) == 0) return 0; rbtree->count--; /* make sure we have at most one non-leaf child */ if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL) { /* swap with smallest from right subtree (or largest from left) */ rbnode_type *smright = to_delete->right; while(smright->left != RBTREE_NULL) smright = smright->left; /* swap the smright and to_delete elements in the tree, * but the rbnode_type is first part of user data struct * so cannot just swap the keys and data pointers. Instead * readjust the pointers left,right,parent */ /* swap colors - colors are tied to the position in the tree */ swap_int8(&to_delete->color, &smright->color); /* swap child pointers in parents of smright/to_delete */ change_parent_ptr(rbtree, to_delete->parent, to_delete, smright); if(to_delete->right != smright) change_parent_ptr(rbtree, smright->parent, smright, to_delete); /* swap parent pointers in children of smright/to_delete */ change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->left, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(smright->right, smright, to_delete); change_child_ptr(to_delete->left, to_delete, smright); if(to_delete->right != smright) change_child_ptr(to_delete->right, to_delete, smright); if(to_delete->right == smright) { /* set up so after swap they work */ to_delete->right = to_delete; smright->parent = smright; } /* swap pointers in to_delete/smright nodes */ swap_np(&to_delete->parent, &smright->parent); swap_np(&to_delete->left, &smright->left); swap_np(&to_delete->right, &smright->right); /* now delete to_delete (which is at the location where the smright previously was) */ } assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL); if(to_delete->left != RBTREE_NULL) child = to_delete->left; else child = to_delete->right; /* unlink to_delete from the tree, replace to_delete with child */ change_parent_ptr(rbtree, to_delete->parent, to_delete, child); change_child_ptr(child, to_delete, to_delete->parent); if(to_delete->color == RED) { /* if node is red then the child (black) can be swapped in */ } else if(child->color == RED) { /* change child to BLACK, removing a RED node is no problem */ if(child!=RBTREE_NULL) child->color = BLACK; } else rbtree_delete_fixup(rbtree, child, to_delete->parent); /* unlink completely */ to_delete->parent = RBTREE_NULL; to_delete->left = RBTREE_NULL; to_delete->right = RBTREE_NULL; to_delete->color = BLACK; return to_delete; } static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, rbnode_type* child_parent) { rbnode_type* sibling; int go_up = 1; /* determine sibling to the node that is one-black short */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; while(go_up) { if(child_parent == RBTREE_NULL) { /* removed parent==black from root, every path, so ok */ return; } if(sibling->color == RED) { /* rotate to get a black sibling */ child_parent->color = RED; sibling->color = BLACK; if(child_parent->right == child) rbtree_rotate_right(rbtree, child_parent); else rbtree_rotate_left(rbtree, child_parent); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } if(child_parent->color == BLACK && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* fixup local with recolor of sibling */ if(sibling != RBTREE_NULL) sibling->color = RED; child = child_parent; child_parent = child_parent->parent; /* prepare to go up, new sibling */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else go_up = 0; } if(child_parent->color == RED && sibling->color == BLACK && sibling->left->color == BLACK && sibling->right->color == BLACK) { /* move red to sibling to rebalance */ if(sibling != RBTREE_NULL) sibling->color = RED; child_parent->color = BLACK; return; } assert(sibling != RBTREE_NULL); /* get a new sibling, by rotating at sibling. See which child of sibling is red */ if(child_parent->right == child && sibling->color == BLACK && sibling->right->color == RED && sibling->left->color == BLACK) { sibling->color = RED; sibling->right->color = BLACK; rbtree_rotate_left(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } else if(child_parent->left == child && sibling->color == BLACK && sibling->left->color == RED && sibling->right->color == BLACK) { sibling->color = RED; sibling->left->color = BLACK; rbtree_rotate_right(rbtree, sibling); /* new sibling after rotation */ if(child_parent->right == child) sibling = child_parent->left; else sibling = child_parent->right; } /* now we have a black sibling with a red child. rotate and exchange colors. */ sibling->color = child_parent->color; child_parent->color = BLACK; if(child_parent->right == child) { assert(sibling->left->color == RED); sibling->left->color = BLACK; rbtree_rotate_right(rbtree, child_parent); } else { assert(sibling->right->color == RED); sibling->right->color = BLACK; rbtree_rotate_left(rbtree, child_parent); } } int rbtree_find_less_equal(rbtree_type *rbtree, const void *key, rbnode_type **result) { int r; rbnode_type *node; assert(result); /* We start at root... */ node = rbtree->root; *result = NULL; /* While there are children... */ while (node != RBTREE_NULL) { r = rbtree->cmp(key, node->key); if (r == 0) { /* Exact match */ *result = node; return 1; } if (r < 0) { node = node->left; } else { /* Temporary match */ *result = node; node = node->right; } } return 0; } /* * Finds the first element in the red black tree * */ rbnode_type * rbtree_first (rbtree_type *rbtree) { rbnode_type *node; for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left); return node; } rbnode_type * rbtree_last (rbtree_type *rbtree) { rbnode_type *node; for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right); return node; } /* * Returns the next node... * */ rbnode_type * rbtree_next (rbnode_type *node) { rbnode_type *parent; if (node->right != RBTREE_NULL) { /* One right, then keep on going left... */ for (node = node->right; node->left != RBTREE_NULL; node = node->left); } else { parent = node->parent; while (parent != RBTREE_NULL && node == parent->right) { node = parent; parent = parent->parent; } node = parent; } return node; } rbnode_type * rbtree_previous(rbnode_type *node) { rbnode_type *parent; if (node->left != RBTREE_NULL) { /* One left, then keep on going right... */ for (node = node->left; node->right != RBTREE_NULL; node = node->right); } else { parent = node->parent; while (parent != RBTREE_NULL && node == parent->left) { node = parent; parent = parent->parent; } node = parent; } return node; } nsd-4.1.26/rrl.c0000664000175000017500000003421213241307322012770 0ustar wouterwouter /* rrl.c - Response Rate Limiting for NSD. * By W.C.A. Wijngaards * Copyright 2012, NLnet Labs. * BSD, see LICENSE. */ #include "config.h" #include #include "rrl.h" #include "util.h" #include "lookup3.h" #include "options.h" #ifdef RATELIMIT #ifdef HAVE_MMAP #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #endif /* HAVE_MMAP */ /** * The rate limiting data structure bucket, this represents one rate of * packets from a single source. * Smoothed average rates. */ struct rrl_bucket { /* the source netmask */ uint64_t source; /* rate, in queries per second, which due to rate=r(t)+r(t-1)/2 is * equal to double the queries per second */ uint32_t rate; /* the full hash */ uint32_t hash; /* counter for queries arrived in this second */ uint32_t counter; /* timestamp, which time is the time of the counter, the rate is from * one timestep before that. */ int32_t stamp; /* flags for the source mask and type */ uint16_t flags; }; /* the (global) array of RRL buckets */ static struct rrl_bucket* rrl_array = NULL; static size_t rrl_array_size = RRL_BUCKETS; static uint32_t rrl_ratelimit = RRL_LIMIT; /* 2x qps */ static uint8_t rrl_slip_ratio = RRL_SLIP; static uint8_t rrl_ipv4_prefixlen = RRL_IPV4_PREFIX_LENGTH; static uint8_t rrl_ipv6_prefixlen = RRL_IPV6_PREFIX_LENGTH; static uint64_t rrl_ipv6_mask; /* max prefixlen 64 */ static uint32_t rrl_whitelist_ratelimit = RRL_WLIST_LIMIT; /* 2x qps */ /* the array of mmaps for the children (saved between reloads) */ static void** rrl_maps = NULL; static size_t rrl_maps_num = 0; void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm, size_t plf, size_t pls) { #ifdef HAVE_MMAP size_t i; #endif if(numbuck != 0) rrl_array_size = numbuck; rrl_ratelimit = lm*2; rrl_slip_ratio = sm; rrl_ipv4_prefixlen = plf; rrl_ipv6_prefixlen = pls; if (pls <= 32) { rrl_ipv6_mask = ((uint64_t) htonl(0xffffffff << (32-pls))) << 32; } else { rrl_ipv6_mask = ((uint64_t) htonl(0xffffffff << (64-pls))) | (((uint64_t)0xffffffff)<<32); } rrl_whitelist_ratelimit = wlm*2; #ifdef HAVE_MMAP /* allocate the ratelimit hashtable in a memory map so it is * preserved across reforks (every child its own table) */ rrl_maps_num = (size_t)numch; rrl_maps = (void**)xmallocarray(rrl_maps_num, sizeof(void*)); for(i=0; i= rrl_maps_num) rrl_array = xalloc_array_zero(sizeof(struct rrl_bucket), rrl_array_size); #ifdef HAVE_MMAP else rrl_array = (struct rrl_bucket*)rrl_maps[ch]; #endif } void rrl_deinit(size_t ch) { if(!rrl_maps || ch >= rrl_maps_num) free(rrl_array); rrl_array = NULL; } /** return the source netblock of the query, this is the genuine source * for genuine queries and the target for reflected packets */ static uint64_t rrl_get_source(query_type* query, uint16_t* c2) { /* note there is an IPv6 subnet, that maps * to the same buckets as IPv4 space, but there is a flag in c2 * that makes the hash different */ #ifdef INET6 if( ((struct sockaddr_in*)&query->addr)->sin_family == AF_INET) { *c2 = 0; return ((struct sockaddr_in*)&query->addr)-> sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); } else { uint64_t s; *c2 = rrl_ip6; memmove(&s, &((struct sockaddr_in6*)&query->addr)->sin6_addr, sizeof(s)); return s & rrl_ipv6_mask; } #else *c2 = 0; return query->addr.sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); #endif } /** debug source to string */ static const char* rrlsource2str(uint64_t s, uint16_t c2) { static char buf[64]; struct in_addr a4; #ifdef INET6 if(c2) { /* IPv6 */ struct in6_addr a6; memset(&a6, 0, sizeof(a6)); memmove(&a6, &s, sizeof(s)); if(!inet_ntop(AF_INET6, &a6, buf, sizeof(buf))) strlcpy(buf, "[ip6 ntop failed]", sizeof(buf)); else { static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv6_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } return buf; } #else (void)c2; #endif /* ipv4 */ a4.s_addr = (uint32_t)s; if(!inet_ntop(AF_INET, &a4, buf, sizeof(buf))) strlcpy(buf, "[ip4 ntop failed]", sizeof(buf)); else { static char prefix[5]; snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv4_prefixlen); strlcat(buf, &prefix[0], sizeof(buf)); } return buf; } enum rrl_type rrlstr2type(const char* s) { if(strcmp(s, "nxdomain")==0) return rrl_type_nxdomain; else if(strcmp(s, "error")==0) return rrl_type_error; else if(strcmp(s, "referral")==0) return rrl_type_referral; else if(strcmp(s, "any")==0) return rrl_type_any; else if(strcmp(s, "wildcard")==0) return rrl_type_wildcard; else if(strcmp(s, "nodata")==0) return rrl_type_nodata; else if(strcmp(s, "dnskey")==0) return rrl_type_dnskey; else if(strcmp(s, "positive")==0) return rrl_type_positive; else if(strcmp(s, "rrsig")==0) return rrl_type_rrsig; else if(strcmp(s, "all")==0) return rrl_type_all; return 0; /* unknown */ } const char* rrltype2str(enum rrl_type c) { switch(c & 0x0fff) { case rrl_type_nxdomain: return "nxdomain"; case rrl_type_error: return "error"; case rrl_type_referral: return "referral"; case rrl_type_any: return "any"; case rrl_type_wildcard: return "wildcard"; case rrl_type_nodata: return "nodata"; case rrl_type_dnskey: return "dnskey"; case rrl_type_positive: return "positive"; case rrl_type_rrsig: return "rrsig"; case rrl_type_all: return "all"; } return "unknown"; } /** classify the query in a number of different types, each has separate * ratelimiting, so that positive queries are not impeded by others */ static uint16_t rrl_classify(query_type* query, const uint8_t** d, size_t* d_len) { if(RCODE(query->packet) == RCODE_NXDOMAIN) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_nxdomain; } if(RCODE(query->packet) != RCODE_OK) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_error; } if(query->delegation_domain) { *d = dname_name(domain_dname(query->delegation_domain)); *d_len = domain_dname(query->delegation_domain)->name_size; return rrl_type_referral; } if(query->qtype == TYPE_ANY) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_any; } if(query->qtype == TYPE_RRSIG) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_rrsig; } if(query->wildcard_domain) { *d = dname_name(domain_dname(query->wildcard_domain)); *d_len = domain_dname(query->wildcard_domain)->name_size; return rrl_type_wildcard; } if(ANCOUNT(query->packet) == 0) { if(query->zone && query->zone->apex) { *d = dname_name(domain_dname(query->zone->apex)); *d_len = domain_dname(query->zone->apex)->name_size; } return rrl_type_nodata; } if(query->qtype == TYPE_DNSKEY) { if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_dnskey; } /* positive */ if(query->qname) { *d = dname_name(query->qname); *d_len = query->qname->name_size; } return rrl_type_positive; } /** Examine the query and return hash and source of netblock. */ static void examine_query(query_type* query, uint32_t* hash, uint64_t* source, uint16_t* flags, uint32_t* lm) { /* compile a binary string representing the query */ uint16_t c, c2; /* size with 16 bytes to spare */ uint8_t buf[MAXDOMAINLEN + sizeof(*source) + sizeof(c) + 16]; const uint8_t* dname = NULL; size_t dname_len = 0; uint32_t r = 0x267fcd16; *source = rrl_get_source(query, &c2); c = rrl_classify(query, &dname, &dname_len); if(query->zone && query->zone->opts && (query->zone->opts->pattern->rrl_whitelist & c)) *lm = rrl_whitelist_ratelimit; if(*lm == 0) return; c |= c2; *flags = c; memmove(buf, source, sizeof(*source)); memmove(buf+sizeof(*source), &c, sizeof(c)); DEBUG(DEBUG_QUERY, 1, (LOG_INFO, "rrl_examine type %s name %s", rrltype2str(c), dname?wiredname2str(dname):"NULL")); /* and hash it */ if(dname && dname_len <= MAXDOMAINLEN) { memmove(buf+sizeof(*source)+sizeof(c), dname, dname_len); *hash = hashlittle(buf, sizeof(*source)+sizeof(c)+dname_len, r); } else *hash = hashlittle(buf, sizeof(*source)+sizeof(c), r); } /* age the bucket because elapsed time steps have gone by */ static void rrl_attenuate_bucket(struct rrl_bucket* b, int32_t elapsed) { if(elapsed > 16) { b->rate = 0; } else { /* divide rate /2 for every elapsed time step, because * the counters in the inbetween steps were 0 */ /* r(t) = 0 + 0/2 + 0/4 + .. + oldrate/2^dt */ b->rate >>= elapsed; /* we know that elapsed >= 2 */ b->rate += (b->counter>>(elapsed-1)); } } /** log a message about ratelimits */ static void rrl_msg(query_type* query, const char* str) { uint16_t c, c2, wl = 0; const uint8_t* d = NULL; size_t d_len; uint64_t s; char address[128]; if(verbosity < 1) return; addr2str(&query->addr, address, sizeof(address)); s = rrl_get_source(query, &c2); c = rrl_classify(query, &d, &d_len) | c2; if(query->zone && query->zone->opts && (query->zone->opts->pattern->rrl_whitelist & c)) wl = 1; log_msg(LOG_INFO, "ratelimit %s %s type %s%s target %s query %s %s", str, d?wiredname2str(d):"", rrltype2str(c), wl?"(whitelisted)":"", rrlsource2str(s, c2), address, rrtype_to_string(query->qtype)); } /** true if the query used to be blocked by the ratelimit */ static int used_to_block(uint32_t rate, uint32_t counter, uint32_t lm) { return rate >= lm || counter+rate/2 >= lm; } /** update the rate in a ratelimit bucket, return actual rate */ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, uint16_t flags, int32_t now, uint32_t lm) { struct rrl_bucket* b = &rrl_array[hash % rrl_array_size]; DEBUG(DEBUG_QUERY, 1, (LOG_INFO, "source %llx hash %x oldrate %d oldcount %d stamp %d", (long long unsigned)source, hash, b->rate, b->counter, b->stamp)); /* check if different source */ if(b->source != source || b->flags != flags || b->hash != hash) { /* initialise */ /* potentially the wrong limit here, used lower nonwhitelim */ if(verbosity >= 1 && used_to_block(b->rate, b->counter, rrl_ratelimit)) { char address[128]; addr2str(&query->addr, address, sizeof(address)); log_msg(LOG_INFO, "ratelimit unblock ~ type %s target %s query %s %s (%s collision)", rrltype2str(b->flags), rrlsource2str(b->source, b->flags), address, rrtype_to_string(query->qtype), (b->hash!=hash?"bucket":"hash")); } b->hash = hash; b->source = source; b->flags = flags; b->counter = 1; b->rate = 0; b->stamp = now; return 1; } /* this is the same source */ /* check if old, zero or smooth it */ /* circular arith for time */ if(now - b->stamp == 1) { /* very busy bucket and time just stepped one step */ int oldblock = used_to_block(b->rate, b->counter, lm); b->rate = b->rate/2 + b->counter; if(oldblock && b->rate < lm) rrl_msg(query, "unblock"); b->counter = 1; b->stamp = now; } else if(now - b->stamp > 0) { /* older bucket */ int olderblock = used_to_block(b->rate, b->counter, lm); rrl_attenuate_bucket(b, now - b->stamp); if(olderblock && b->rate < lm) rrl_msg(query, "unblock"); b->counter = 1; b->stamp = now; } else if(now != b->stamp) { /* robust, timestamp from the future */ if(used_to_block(b->rate, b->counter, lm)) rrl_msg(query, "unblock"); b->rate = 0; b->counter = 1; b->stamp = now; } else { /* bucket is from the current timestep, update counter */ b->counter ++; /* log what is blocked for operational debugging */ if(b->counter + b->rate/2 == lm && b->rate < lm) rrl_msg(query, "block"); } /* return max from current rate and projected next-value for rate */ /* so that if the rate increases suddenly very high, it is * stopped halfway into the time step */ if(b->counter > b->rate/2) return b->counter + b->rate/2; return b->rate; } int rrl_process_query(query_type* query) { uint64_t source; uint32_t hash; /* we can use circular arithmetic here, so int32 works after 2038 */ int32_t now = (int32_t)time(NULL); uint32_t lm = rrl_ratelimit; uint16_t flags; if(rrl_ratelimit == 0 && rrl_whitelist_ratelimit == 0) return 0; /* examine query */ examine_query(query, &hash, &source, &flags, &lm); if(lm == 0) return 0; /* no limit for this */ /* update rate */ return (rrl_update(query, hash, source, flags, now, lm) >= lm); } query_state_type rrl_slip(query_type* query) { /* discard number the packets, randomly */ #ifdef HAVE_ARC4RANDOM_UNIFORM if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random_uniform(rrl_slip_ratio)) == 0))) { #elif HAVE_ARC4RANDOM if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random() % rrl_slip_ratio) == 0))) { #else if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((random() % rrl_slip_ratio) == 0))) { #endif /* set TC on the rest */ TC_SET(query->packet); ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); if(query->qname) /* header, type, class, qname */ buffer_set_position(query->packet, QHEADERSZ+4+query->qname->name_size); else buffer_set_position(query->packet, QHEADERSZ); return QUERY_PROCESSED; } return QUERY_DISCARDED; } #endif /* RATELIMIT */ nsd-4.1.26/xfrd-tcp.h0000664000175000017500000001473713040156013013733 0ustar wouterwouter/* * xfrd-tcp.h - XFR (transfer) Daemon TCP system header file. Manages tcp conn. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_TCP_H #define XFRD_TCP_H #include "xfrd.h" struct buffer; struct xfrd_zone; struct xfrd_soa; struct xfrd_state; struct region; struct dname; struct acl_options; struct xfrd_tcp_pipeline; typedef struct xfrd_tcp xfrd_tcp_type; typedef struct xfrd_tcp_set xfrd_tcp_set_type; /* * A set of xfrd tcp connections. */ struct xfrd_tcp_set { /* tcp connections, each has packet and read/wr state */ struct xfrd_tcp_pipeline *tcp_state[XFRD_MAX_TCP]; /* number of TCP connections in use. */ int tcp_count; /* TCP timeout. */ int tcp_timeout; /* rbtree with pipelines sorted by master */ rbtree_type* pipetree; /* double linked list of zones waiting for a TCP connection */ struct xfrd_zone *tcp_waiting_first, *tcp_waiting_last; }; /* * Structure to keep track of an open tcp connection * The xfrd tcp connection is used to first make a request * Then to receive the answer packet(s). */ struct xfrd_tcp { /* tcp connection state */ /* state: reading or writing */ uint8_t is_reading; /* how many bytes have been read/written - total, incl. tcp length bytes */ uint32_t total_bytes; /* msg len bytes */ uint16_t msglen; /* fd of connection. -1 means unconnected */ int fd; /* packet buffer of connection */ struct buffer* packet; }; /* use illegal pointer value to denote skipped ID number. * if this does not work, we can allocate with malloc */ #define TCP_NULL_SKIP ((struct xfrd_zone*)-1) /* the number of ID values (16 bits) for a pipeline */ #define ID_PIPE_NUM 65536 /** * Structure to keep track of a pipelined set of queries on * an open tcp connection. The queries may be answered with * interleaved answer packets, the ID number disambiguates. * Sorted by the master IP address so you can use lookup with * smaller-or-equal to find the tcp connection most suitable. */ struct xfrd_tcp_pipeline { /* the rbtree node, sorted by IP and nr of unused queries */ rbnode_type node; /* destination IP address */ #ifdef INET6 struct sockaddr_storage ip; #else struct sockaddr_in ip; #endif /* INET6 */ socklen_t ip_len; /* number of unused IDs. used IDs are waiting to send their query, * or have been sent but not not all answer packets have been received. * Sorted by num_unused, so a lookup smaller-equal for 65536 finds the * connection to that master that has the most free IDs. */ int num_unused; /* number of skip-set IDs (these are 'in-use') */ int num_skip; int handler_added; /* the event handler for this pipe (it'll disambiguate by ID) */ struct event handler; /* the tcp connection to use for reading */ struct xfrd_tcp* tcp_r; /* the tcp connection to use for writing, if it is done successfully, * then the first zone from the sendlist can be removed. */ struct xfrd_tcp* tcp_w; /* once a byte has been written, handshake complete */ int connection_established; /* list of queries that want to send, first to get write event, * if NULL, no write event interest */ struct xfrd_zone* tcp_send_first, *tcp_send_last; /* the unused and id arrays must be last in the structure */ /* per-ID number the queries that have this ID number, every * query owns one ID numbers (until it is done). NULL: unused * When a query is done but not all answer-packets have been * consumed for that ID number, the rest is skipped, this * is denoted with the pointer-value TCP_NULL_SKIP, the ids that * are skipped are not on the unused list. They may be * removed once the last answer packet is skipped. * ID_PIPE_NUM-num_unused values in the id array are nonNULL (either * a zone pointer or SKIP) */ struct xfrd_zone* id[ID_PIPE_NUM]; /* unused ID numbers; the first part of the array contains the IDs */ uint16_t unused[ID_PIPE_NUM]; }; /* create set of tcp connections */ struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region); /* init tcp state */ struct xfrd_tcp* xfrd_tcp_create(struct region* region, size_t bufsize); /* obtain tcp connection for a zone (or wait) */ void xfrd_tcp_obtain(struct xfrd_tcp_set* set, struct xfrd_zone* zone); /* release tcp connection for a zone (starts waiting) */ void xfrd_tcp_release(struct xfrd_tcp_set* set, struct xfrd_zone* zone); /* release tcp pipe entirely (does not stop the zones inside it) */ void xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, int conn); /* use tcp connection to start xfr */ void xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* initialize tcp_state for a zone. Opens the connection. true on success.*/ int xfrd_tcp_open(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* read data from tcp, maybe partial read */ void xfrd_tcp_read(struct xfrd_tcp_pipeline* tp); /* write data to tcp, maybe a partial write */ void xfrd_tcp_write(struct xfrd_tcp_pipeline* tp, struct xfrd_zone* zone); /* handle tcp pipe events */ void xfrd_handle_tcp_pipe(int fd, short event, void* arg); /* * Read from a stream connection (size16)+packet into buffer. * returns value is * -1 on error. * 0 on short read, call back later. * 1 on completed read. * On first call, make sure total_bytes = 0, msglen=0, buffer_clear(). * and the packet and fd need to be set. */ int conn_read(struct xfrd_tcp* conn); /* * Write to a stream connection (size16)+packet. * return value is * -1 on error. 0 on short write, call back later. 1 completed write. * On first call, make sure total_bytes=0, msglen=buffer_limit(), * buffer_flipped(). packet and fd need to be set. */ int conn_write(struct xfrd_tcp* conn); /* setup DNS packet for a query of this type */ void xfrd_setup_packet(struct buffer* packet, uint16_t type, uint16_t klass, const struct dname* dname, uint16_t qid); /* write soa in network format to the packet buffer */ void xfrd_write_soa_buffer(struct buffer* packet, const struct dname* apex, struct xfrd_soa* soa); /* use acl address to setup sockaddr struct, returns length of addr. */ socklen_t xfrd_acl_sockaddr_to(struct acl_options* acl, #ifdef INET6 struct sockaddr_storage *to); #else struct sockaddr_in *to); #endif /* INET6 */ socklen_t xfrd_acl_sockaddr_frm(struct acl_options* acl, #ifdef INET6 struct sockaddr_storage *frm); #else struct sockaddr_in *frm); #endif /* INET6 */ /* create pipeline tcp structure */ struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region); #endif /* XFRD_TCP_H */ nsd-4.1.26/zlexer.lex0000664000175000017500000002336213212167563014065 0ustar wouterwouter%{ /* * zlexer.lex - lexical analyzer for (DNS) zone files * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif /* ignore fallthrough warnings in the generated parse code case statements */ #if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__ >=7)) #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif #include "config.h" #include #include #include #include #include "zonec.h" #include "dname.h" #include "zparser.h" #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif enum lexer_state { EXPECT_OWNER, PARSING_OWNER, PARSING_TTL_CLASS_TYPE, PARSING_RDATA }; static int parse_token(int token, char *yytext, enum lexer_state *lexer_state); static YY_BUFFER_STATE include_stack[MAXINCLUDES]; static zparser_type zparser_stack[MAXINCLUDES]; static int include_stack_ptr = 0; /* * Saves the file specific variables on the include stack. */ static void push_parser_state(FILE *input) { zparser_stack[include_stack_ptr].filename = parser->filename; zparser_stack[include_stack_ptr].line = parser->line; zparser_stack[include_stack_ptr].origin = parser->origin; include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); ++include_stack_ptr; } /* * Restores the file specific variables from the include stack. */ static void pop_parser_state(void) { --include_stack_ptr; parser->filename = zparser_stack[include_stack_ptr].filename; parser->line = zparser_stack[include_stack_ptr].line; parser->origin = zparser_stack[include_stack_ptr].origin; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(include_stack[include_stack_ptr]); } static YY_BUFFER_STATE oldstate; /* Start string scan */ void parser_push_stringbuf(char* str) { oldstate = YY_CURRENT_BUFFER; yy_switch_to_buffer(yy_scan_string(str)); } void parser_pop_stringbuf(void) { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(oldstate); 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) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif %} %option noinput %option nounput %{ #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif %} SPACE [ \t] LETTER [a-zA-Z] NEWLINE [\n\r] ZONESTR [^ \t\n\r();.\"\$]|\\.|\\\n CHARSTR [^ \t\n\r();.]|\\.|\\\n QUOTE \" DOLLAR \$ COMMENT ; DOT \. BIT [^\]\n]|\\. ANY [^\"\n\\]|\\. %x incl bitlabel quotedstring %% {SPACE}*{COMMENT}.* /* ignore */ ^{DOLLAR}TTL { lexer_state = PARSING_RDATA; return DOLLAR_TTL; } ^{DOLLAR}ORIGIN { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; } /* * Handle $INCLUDE directives. See * http://dinosaur.compilertools.net/flex/flex_12.html#SEC12. */ ^{DOLLAR}INCLUDE { BEGIN(incl); /* ignore case statement fallthrough on incl flex rule */ } \n | <> { int error_occurred = parser->error_occurred; BEGIN(INITIAL); zc_error("missing file name in $INCLUDE directive"); yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ ++parser->line; parser->error_occurred = error_occurred; } .+ { char *tmp; domain_type *origin = parser->origin; int error_occurred = parser->error_occurred; BEGIN(INITIAL); if (include_stack_ptr >= MAXINCLUDES ) { zc_error("includes nested too deeply, skipped (>%d)", MAXINCLUDES); } else { FILE *input; /* Remove trailing comment. */ tmp = strrchr(yytext, ';'); if (tmp) { *tmp = '\0'; } strip_string(yytext); /* Parse origin for include file. */ tmp = strrchr(yytext, ' '); if (!tmp) { tmp = strrchr(yytext, '\t'); } if (tmp) { const dname_type *dname; /* split the original yytext */ *tmp = '\0'; strip_string(yytext); dname = dname_parse(parser->region, tmp + 1); if (!dname) { zc_error("incorrect include origin '%s'", tmp + 1); } else if (*(tmp + strlen(tmp + 1)) != '.') { zc_error("$INCLUDE directive requires absolute domain name"); } else { origin = domain_table_insert( parser->db->domains, dname); } } if (strlen(yytext) == 0) { zc_error("missing file name in $INCLUDE directive"); } else if (!(input = fopen(yytext, "r"))) { zc_error("cannot open include file '%s': %s", yytext, strerror(errno)); } else { /* Initialize parser for include file. */ char *filename = region_strdup(parser->region, yytext); push_parser_state(input); /* Destroys yytext. */ parser->filename = filename; parser->line = 1; parser->origin = origin; lexer_state = EXPECT_OWNER; } } parser->error_occurred = error_occurred; } <> { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (include_stack_ptr == 0) { yyterminate(); } else { fclose(yyin); pop_parser_state(); } } ^{DOLLAR}{LETTER}+ { zc_warning("Unknown directive: %s", yytext); } {DOT} { LEXOUT((". ")); return parse_token('.', yytext, &lexer_state); } @ { LEXOUT(("@ ")); return parse_token('@', yytext, &lexer_state); } \\# { LEXOUT(("\\# ")); return parse_token(URR, yytext, &lexer_state); } {NEWLINE} { ++parser->line; if (!paren_open) { lexer_state = EXPECT_OWNER; LEXOUT(("NL\n")); return NL; } else { LEXOUT(("SP ")); return SP; } } \( { if (paren_open) { zc_error("nested parentheses"); yyterminate(); } LEXOUT(("( ")); paren_open = 1; return SP; } \) { if (!paren_open) { zc_error("closing parentheses without opening parentheses"); yyterminate(); } LEXOUT((") ")); paren_open = 0; return SP; } {SPACE}+ { if (!paren_open && lexer_state == EXPECT_OWNER) { lexer_state = PARSING_TTL_CLASS_TYPE; LEXOUT(("PREV ")); return PREV; } if (lexer_state == PARSING_OWNER) { lexer_state = PARSING_TTL_CLASS_TYPE; } LEXOUT(("SP ")); return SP; } /* Bitlabels. Strip leading and ending brackets. */ \\\[ { BEGIN(bitlabel); } <> { zc_error("EOF inside bitlabel"); BEGIN(INITIAL); yyrestart(yyin); /* this is so that lex does not give an internal err */ yyterminate(); } {BIT}* { yymore(); } \n { ++parser->line; yymore(); } \] { BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; return parse_token(BITLAB, yytext, &lexer_state); } /* Quoted strings. Strip leading and ending quotes. */ {QUOTE} { BEGIN(quotedstring); LEXOUT(("\" ")); } <> { zc_error("EOF inside quoted string"); BEGIN(INITIAL); yyrestart(yyin); /* this is so that lex does not give an internal err */ yyterminate(); } {ANY}* { LEXOUT(("STR ")); yymore(); } \n { ++parser->line; yymore(); } {QUOTE} { LEXOUT(("\" ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; return parse_token(STR, yytext, &lexer_state); } {ZONESTR}({CHARSTR})* { /* Any allowed word. */ return parse_token(STR, yytext, &lexer_state); } . { zc_error("unknown character '%c' (\\%03d) seen - is this a zonefile?", (int) yytext[0], (int) yytext[0]); } %% /* * Analyze "word" to see if it matches an RR type, possibly by using * the "TYPExxx" notation. If it matches, the corresponding token is * returned and the TYPE parameter is set to the RR type value. */ static int rrtype_to_token(const char *word, uint16_t *type) { uint16_t t = rrtype_from_string(word); if (t != 0) { rrtype_descriptor_type *entry = rrtype_descriptor_by_type(t); *type = t; return entry->token; } return 0; } /* * Remove \DDD constructs from the input. See RFC 1035, section 5.1. */ static size_t zoctet(char *text) { /* * s follows the string, p lags behind and rebuilds the new * string */ char *s; char *p; for (s = p = text; *s; ++s, ++p) { assert(p <= s); if (s[0] != '\\') { /* Ordinary character. */ *p = *s; } else if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) { /* \DDD escape. */ int val = (hexdigit_to_int(s[1]) * 100 + hexdigit_to_int(s[2]) * 10 + hexdigit_to_int(s[3])); if (0 <= val && val <= 255) { s += 3; *p = val; } else { zc_warning("text escape \\DDD overflow"); *p = *++s; } } else if (s[1] != '\0') { /* \X where X is any character, keep X. */ *p = *++s; } else { /* Trailing backslash, ignore it. */ zc_warning("trailing backslash ignored"); --p; } } *p = '\0'; return p - text; } static int parse_token(int token, char *yytext, enum lexer_state *lexer_state) { size_t len; char *str; if (*lexer_state == EXPECT_OWNER) { *lexer_state = PARSING_OWNER; } else if (*lexer_state == PARSING_TTL_CLASS_TYPE) { const char *t; int token; uint16_t rrclass; /* type */ token = rrtype_to_token(yytext, &yylval.type); if (token != 0) { *lexer_state = PARSING_RDATA; LEXOUT(("%d[%s] ", token, yytext)); return token; } /* class */ rrclass = rrclass_from_string(yytext); if (rrclass != 0) { yylval.klass = rrclass; LEXOUT(("CLASS ")); return T_RRCLASS; } /* ttl */ yylval.ttl = strtottl(yytext, &t); if (*t == '\0') { LEXOUT(("TTL ")); return T_TTL; } } str = region_strdup(parser->rr_region, yytext); len = zoctet(str); yylval.data.str = str; yylval.data.len = len; LEXOUT(("%d[%s] ", token, yytext)); return token; } nsd-4.1.26/zonec.h0000664000175000017500000001264313157751374013340 0ustar wouterwouter/* * zonec.h -- zone compiler. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _ZONEC_H_ #define _ZONEC_H_ #include "namedb.h" #define MAXTOKENSLEN 512 /* Maximum number of tokens per entry */ #define B64BUFSIZE 65535 /* Buffer size for b64 conversion */ #define ROOT (const uint8_t *)"\001" #define NSEC_WINDOW_COUNT 256 #define NSEC_WINDOW_BITS_COUNT 256 #define NSEC_WINDOW_BITS_SIZE (NSEC_WINDOW_BITS_COUNT / 8) #define IPSECKEY_NOGATEWAY 0 /* RFC 4025 */ #define IPSECKEY_IP4 1 #define IPSECKEY_IP6 2 #define IPSECKEY_DNAME 3 #define LINEBUFSZ 1024 struct lex_data { size_t len; /* holds the label length */ char *str; /* holds the data */ }; #define DEFAULT_TTL 3600 /* administration struct */ typedef struct zparser zparser_type; struct zparser { region_type *region; /* Allocate for parser lifetime data. */ region_type *rr_region; /* Allocate RR lifetime data. */ namedb_type *db; const char *filename; uint32_t default_ttl; uint16_t default_class; zone_type *current_zone; domain_type *origin; domain_type *prev_dname; domain_type *default_apex; int error_occurred; unsigned int errors; unsigned int line; rr_type current_rr; rdata_atom_type *temporary_rdatas; }; extern zparser_type *parser; /* used in zonec.lex */ extern FILE *yyin; /* * Used to mark bad domains and domain names. Do not dereference * these pointers! */ extern const dname_type *error_dname; extern domain_type *error_domain; int yyparse(void); int yylex(void); int yylex_destroy(void); /*int yyerror(const char *s);*/ void yyrestart(FILE *); void zc_warning(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2); void zc_warning_prev_line(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2); void zc_error(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2); 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); uint16_t *zparser_conv_hex_length(region_type *region, const char *hex, size_t len); uint16_t *zparser_conv_time(region_type *region, const char *time); uint16_t *zparser_conv_services(region_type *region, const char *protostr, char *servicestr); uint16_t *zparser_conv_serial(region_type *region, const char *periodstr); uint16_t *zparser_conv_period(region_type *region, const char *periodstr); uint16_t *zparser_conv_short(region_type *region, const char *text); uint16_t *zparser_conv_long(region_type *region, const char *text); uint16_t *zparser_conv_byte(region_type *region, const char *text); uint16_t *zparser_conv_a(region_type *region, const char *text); uint16_t *zparser_conv_aaaa(region_type *region, const char *text); uint16_t *zparser_conv_ilnp64(region_type *region, const char *text); uint16_t *zparser_conv_eui(region_type *region, const char *text, size_t len); uint16_t *zparser_conv_text(region_type *region, const char *text, size_t len); uint16_t *zparser_conv_long_text(region_type *region, const char *text, size_t len); uint16_t *zparser_conv_tag(region_type *region, const char *text, size_t len); uint16_t *zparser_conv_dns_name(region_type *region, const uint8_t* name, size_t len); uint16_t *zparser_conv_b32(region_type *region, const char *b32); uint16_t *zparser_conv_b64(region_type *region, const char *b64); uint16_t *zparser_conv_rrtype(region_type *region, const char *rr); uint16_t *zparser_conv_nxt(region_type *region, uint8_t nxtbits[]); uint16_t *zparser_conv_nsec(region_type *region, uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]); uint16_t *zparser_conv_loc(region_type *region, char *str); uint16_t *zparser_conv_algorithm(region_type *region, const char *algstr); uint16_t *zparser_conv_certificate_type(region_type *region, const char *typestr); uint16_t *zparser_conv_apl_rdata(region_type *region, char *str); void parse_unknown_rdata(uint16_t type, uint16_t *wireformat); uint32_t zparser_ttl2int(const char *ttlstr, int* error); void zadd_rdata_wireformat(uint16_t *data); void zadd_rdata_txt_wireformat(uint16_t *data, int first); void zadd_rdata_txt_clean_wireformat(); void zadd_rdata_domain(domain_type *domain); void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], uint16_t index); uint16_t *alloc_rdata_init(region_type *region, const void *data, size_t size); /* zparser.y */ zparser_type *zparser_create(region_type *region, region_type *rr_region, namedb_type *db); void zparser_init(const char *filename, uint32_t ttl, uint16_t klass, const dname_type *origin); /* parser start and stop to parse a zone */ void zonec_setup_parser(namedb_type* db); void zonec_desetup_parser(void); /* parse a zone into memory. name is origin. zonefile is file to read. * returns number of errors; failure may have read a partial zone */ unsigned int zonec_read(const char *name, const char *zonefile, zone_type* zone); /* parse a string into the region. and with given domaintable. global parser * is restored afterwards. zone needs apex set. returns last domain name * parsed and the number rrs parse. return number of errors, 0 is success. * The string must end with a newline after the RR. */ int zonec_parse_string(region_type* region, domain_table_type* domains, zone_type* zone, char* str, domain_type** parsed, int* num_rrs); #endif /* _ZONEC_H_ */ nsd-4.1.26/namedb.h0000664000175000017500000003222713200057161013426 0ustar wouterwouter/* * namedb.h -- nsd(8) internal namespace database definitions * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _NAMEDB_H_ #define _NAMEDB_H_ #include #include "dname.h" #include "dns.h" #include "radtree.h" #include "rbtree.h" struct zone_options; struct nsd_options; struct udb_base; struct udb_ptr; struct nsd; typedef union rdata_atom rdata_atom_type; typedef struct rrset rrset_type; typedef struct rr rr_type; /* * A domain name table supporting fast insert and search operations. */ typedef struct domain_table domain_table_type; typedef struct domain domain_type; typedef struct zone zone_type; typedef struct namedb namedb_type; struct domain_table { region_type* region; #ifdef USE_RADIX_TREE struct radtree *nametree; #else rbtree_type *names_to_domains; #endif domain_type* root; /* ptr to biggest domain.number and last in list. * the root is the lowest and first in the list. */ domain_type *numlist_last; #ifdef NSEC3 /* the prehash list, start of the list */ domain_type* prehash_list; #endif /* NSEC3 */ }; #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; /* the nsec3 that covers the wildcard child of this domain. */ domain_type* nsec3_wcard_child_cover; /* for the DS case we must answer on the parent side of zone cut */ domain_type* nsec3_ds_parent_cover; /* NSEC3 domains to prehash, prev and next on the list or cleared */ domain_type* prehash_prev, *prehash_next; /* entry in the nsec3tree (for NSEC3s in the chain in use) */ rbnode_type nsec3_node; /* 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 { #ifdef USE_RADIX_TREE struct radnode* rnode; const dname_type* dname; #else rbnode_type node; #endif domain_type* parent; domain_type* wildcard_child_closest_match; rrset_type* rrsets; #ifdef NSEC3 struct nsec3_domain_data* nsec3; #endif /* double-linked list sorted by domain.number */ domain_type* numlist_prev, *numlist_next; 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. */ /* * This domain name exists (see wildcard clarification draft). */ unsigned is_existing : 1; unsigned is_apex : 1; } ATTR_PACKED; struct zone { struct radnode *node; /* this entry in zonetree */ domain_type* apex; rrset_type* soa_rrset; rrset_type* soa_nx_rrset; /* see bug #103 */ rrset_type* ns_rrset; #ifdef NSEC3 rr_type* nsec3_param; /* NSEC3PARAM RR of chain in use or NULL */ domain_type* nsec3_last; /* last domain with nsec3, wraps */ /* in these trees, the root contains an elem ptr to the radtree* */ rbtree_type* nsec3tree; /* tree with relevant NSEC3 domains */ rbtree_type* hashtree; /* tree, hashed NSEC3precompiled domains */ rbtree_type* wchashtree; /* tree, wildcard hashed domains */ rbtree_type* dshashtree; /* tree, ds-parent-hash domains */ #endif struct zone_options* opts; char* filename; /* set if read from file, which file */ char* logstr; /* set for zone xfer, the log string */ struct timespec mtime; /* time of last modification */ unsigned zonestatid; /* array index for zone stats */ 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 { domain_type* owner; rdata_atom_type* rdatas; uint32_t ttl; 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. */ struct rrset { rrset_type* next; 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. * The allowed wireformats are defined by the rdata_wireformat_type * enumeration. */ union rdata_atom { /* RDATA_WF_COMPRESSED_DNAME, RDATA_WF_UNCOMPRESSED_DNAME */ domain_type* domain; /* Default. */ uint16_t* data; }; /* * Create a new domain_table containing only the root domain. */ domain_table_type *domain_table_create(region_type *region); /* * Search the domain table for a match and the closest encloser. */ int domain_table_search(domain_table_type* table, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser); /* * The number of domains stored in the table (minimum is one for the * root domain). */ static inline uint32_t domain_table_count(domain_table_type* table) { #ifdef USE_RADIX_TREE return table->nametree->count; #else return table->names_to_domains->count; #endif } /* * Find the specified dname in the domain_table. NULL is returned if * there is no exact match. */ domain_type* domain_table_find(domain_table_type* table, const dname_type* dname); /* * Insert a domain name in the domain table. If the domain name is * not yet present in the table it is copied and a new dname_info node * is created (as well as for the missing parent domain names, if * any). Otherwise the domain_type that is already in the * domain_table is returned. */ domain_type *domain_table_insert(domain_table_type *table, const dname_type *dname); /* put domain into nsec3 hash space tree */ void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree, int (*cmpf)(const void*, const void*), domain_type* domain, rbnode_type* node); void zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node); void hash_tree_clear(rbtree_type* tree); void hash_tree_delete(region_type* region, rbtree_type* tree); void prehash_clear(domain_table_type* table); void prehash_add(domain_table_type* table, domain_type* domain); void prehash_del(domain_table_type* table, domain_type* domain); int domain_is_prehash(domain_table_type* table, domain_type* domain); /* * Add an RRset to the specified domain. Updates the is_existing flag * as required. */ void domain_add_rrset(domain_type* domain, rrset_type* rrset); rrset_type* domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type); rrset_type* domain_find_any_rrset(domain_type* domain, zone_type* zone); zone_type* domain_find_zone(namedb_type* db, domain_type* domain); zone_type* domain_find_parent_zone(namedb_type* db, zone_type* zone); domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns); /* find DNAME rrset in domain->parent or higher and return that domain */ domain_type * find_dname_above(domain_type* domain, zone_type* zone); int domain_is_glue(domain_type* domain, zone_type* zone); rrset_type* domain_find_non_cname_rrset(domain_type* domain, zone_type* zone); domain_type* domain_wildcard_child(domain_type* domain); domain_type *domain_previous_existing_child(domain_type* domain); int zone_is_secure(zone_type* zone); static inline dname_type * domain_dname(domain_type* domain) { #ifdef USE_RADIX_TREE return (dname_type *) domain->dname; #else return (dname_type *) domain->node.key; #endif } static inline const dname_type * domain_dname_const(const domain_type* domain) { #ifdef USE_RADIX_TREE return domain->dname; #else return (const dname_type *) domain->node.key; #endif } static inline domain_type * domain_previous(domain_type* domain) { #ifdef USE_RADIX_TREE struct radnode* prev = radix_prev(domain->rnode); return prev == NULL ? NULL : (domain_type*)prev->elem; #else rbnode_type *prev = rbtree_previous((rbnode_type *) domain); return prev == RBTREE_NULL ? NULL : (domain_type *) prev; #endif } static inline domain_type * domain_next(domain_type* domain) { #ifdef USE_RADIX_TREE struct radnode* next = radix_next(domain->rnode); return next == NULL ? NULL : (domain_type*)next->elem; #else rbnode_type *next = rbtree_next((rbnode_type *) domain); return next == RBTREE_NULL ? NULL : (domain_type *) next; #endif } /* easy comparison for subdomain, true if d1 is subdomain of d2. */ static inline int domain_is_subdomain(domain_type* d1, domain_type* d2) { return dname_is_subdomain(domain_dname(d1), domain_dname(d2)); } /* easy printout, to static buffer of dname_to_string, fqdn. */ static inline const char* domain_to_string(domain_type* domain) { return dname_to_string(domain_dname(domain), NULL); } /* * The type covered by the signature in the specified RRSIG RR. */ uint16_t rr_rrsig_type_covered(rr_type* rr); struct namedb { region_type* region; domain_table_type* domains; struct radtree* zonetree; struct udb_base* udb; /* the timestamp on the ixfr.db file */ struct timeval diff_timestamp; /* if diff_skip=1, diff_pos contains the nsd.diff place to continue */ uint8_t diff_skip; off_t diff_pos; }; static inline int rdata_atom_is_domain(uint16_t type, size_t index); static inline int rdata_atom_is_literal_domain(uint16_t type, size_t index); static inline domain_type * rdata_atom_domain(rdata_atom_type atom) { return atom.domain; } static inline uint16_t rdata_atom_size(rdata_atom_type atom) { return *atom.data; } static inline uint8_t * rdata_atom_data(rdata_atom_type atom) { return (uint8_t *) (atom.data + 1); } /* Find the zone for the specified dname in DB. */ zone_type *namedb_find_zone(namedb_type *db, const dname_type *dname); /* * Delete a domain name from the domain table. Removes dname_info node. * Only deletes if usage is 0, has no rrsets and no children. Checks parents * for deletion as well. Adjusts numberlist(domain.number), and * wcard_child closest match. */ void domain_table_deldomain(namedb_type* db, domain_type* domain); /** dbcreate.c */ int udb_write_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr); void udb_del_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr); int write_zone_to_udb(struct udb_base* udb, zone_type* zone, struct timespec* mtime, const char* file_str); /** marshal rdata into buffer, must be MAX_RDLENGTH in size */ size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz); /* dbaccess.c */ int namedb_lookup (struct namedb* db, const dname_type* dname, domain_type **closest_match, domain_type **closest_encloser); /* pass number of children (to alloc in dirty array */ struct namedb *namedb_open(const char *filename, struct nsd_options* opt); void namedb_close_udb(struct namedb* db); void namedb_close(struct namedb* db); void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt, struct udb_base* taskudb, struct udb_ptr* last_task); void namedb_check_zonefile(struct nsd* nsd, struct udb_base* taskudb, struct udb_ptr* last_task, struct zone_options* zo); /** zone one zonefile into memory and revert on parse error, write to udb */ void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, struct udb_base* taskudb, struct udb_ptr* last_task); void apex_rrset_checks(struct namedb* db, rrset_type* rrset, domain_type* domain); zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zopt); void namedb_zone_delete(namedb_type* db, zone_type* zone); void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt); void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options); int create_dirs(const char* path); int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist); void allocate_domain_nsec3(domain_table_type *table, domain_type *result); static inline int rdata_atom_is_domain(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); return (index < descriptor->maximum && (descriptor->wireformat[index] == RDATA_WF_COMPRESSED_DNAME || descriptor->wireformat[index] == RDATA_WF_UNCOMPRESSED_DNAME)); } static inline int rdata_atom_is_literal_domain(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); return (index < descriptor->maximum && (descriptor->wireformat[index] == RDATA_WF_LITERAL_DNAME)); } static inline rdata_wireformat_type rdata_atom_wireformat_type(uint16_t type, size_t index) { const rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(type); assert(index < descriptor->maximum); return (rdata_wireformat_type) descriptor->wireformat[index]; } static inline uint16_t rrset_rrtype(rrset_type* rrset) { assert(rrset); assert(rrset->rr_count > 0); return rrset->rrs[0].type; } static inline uint16_t rrset_rrclass(rrset_type* rrset) { assert(rrset); assert(rrset->rr_count > 0); return rrset->rrs[0].klass; } #endif nsd-4.1.26/rdata.h0000664000175000017500000000326710461666637013321 0ustar wouterwouter/* * rdata.h -- RDATA conversion functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _RDATA_H_ #define _RDATA_H_ #include "dns.h" #include "namedb.h" /* High bit of the APL length field is the negation bit. */ #define APL_NEGATION_MASK 0x80U #define APL_LENGTH_MASK (~APL_NEGATION_MASK) extern lookup_table_type dns_certificate_types[]; extern lookup_table_type dns_algorithms[]; int rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type, rdata_atom_type rdata, rr_type *rr); /* * Split the wireformat RDATA into an array of rdata atoms. Domain * names are inserted into the OWNERS table. The number of rdata atoms * is returned and the array itself is allocated in REGION and stored * in RDATAS. * * Returns -1 on failure. */ ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t rdata_size, buffer_type *packet, rdata_atom_type **rdatas); /* * Calculate the maximum size of the rdata assuming domain names are * not compressed. */ size_t rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas); int rdata_atoms_to_unknown_string(buffer_type *out, rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas); /* print rdata to a text string (as for a zone file) returns 0 on a failure (bufpos is reset to original position). returns 1 on success, bufpos is moved. */ int print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor, rr_type *record); #endif /* _DNS_H_ */ nsd-4.1.26/configure.ac0000664000175000017500000010301413355417226014323 0ustar wouterwouterdnl dnl Some global settings dnl sinclude(acx_nlnetlabs.m4) sinclude(dnstap/dnstap.m4) AC_INIT(NSD,4.1.26,nsd-bugs@nlnetlabs.nl) AC_CONFIG_HEADER([config.h]) CFLAGS="$CFLAGS" AC_AIX if test "$ac_cv_header_minix_config_h" = "yes"; then AC_DEFINE(_NETBSD_SOURCE,1, [Enable for compile on Minix]) fi dnl dnl By default set $sysconfdir to /etc and $localstatedir to /var dnl case "$prefix" in NONE) case "$sysconfdir" in '${prefix}/etc') sysconfdir=/etc ;; esac case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac ;; esac # # Determine configuration directory # configdir=$sysconfdir/nsd AC_ARG_WITH([configdir], AC_HELP_STRING([--with-configdir=dir], [NSD configuration directory]), [configdir=$withval]) AC_DEFINE_UNQUOTED(CONFIGDIR, ["`eval echo $configdir`"], [NSD config dir]) AC_SUBST(configdir) # # Determine configuration file nsd_conf_file=${configdir}/nsd.conf AC_ARG_WITH([nsd_conf_file], AC_HELP_STRING([--with-nsd_conf_file=path], [Pathname to the NSD configuration file]), [nsd_conf_file=$withval]) AC_SUBST(nsd_conf_file) # the eval is to evaluate shell expansion twice, once # for $nsd_conf_file and once for the ${prefix} within it. AC_DEFINE_UNQUOTED(CONFIGFILE, ["`eval echo $nsd_conf_file`"], [Pathname to the NSD configuration file]) # # Default logfile # logfile=${localstatedir}/log/nsd.log AC_ARG_WITH([logfile], AC_HELP_STRING([--with-logfile=path], [Pathname to the default log file]), [logfile=$withval]) AC_SUBST(logfile) # # Database directory # dbdir=${localstatedir}/db/nsd # # Determine the pidfile location. Check if /var/run exists, if so set pidfile # to /var/run/nsd.pid by default # if test -d ${localstatedir}/run; then pidfile=${localstatedir}/run/nsd.pid else pidfile=${dbdir}/nsd.pid fi AC_ARG_WITH([pidfile], AC_HELP_STRING([--with-pidfile=path], [Pathname to the NSD pidfile]), [pidfile=$withval]) AC_SUBST(pidfile) AC_DEFINE_UNQUOTED(PIDFILE, ["`eval echo $pidfile`"], [Pathname to the NSD pidfile]) # # Determine location of nsd.db # dbfile=${dbdir}/nsd.db AC_ARG_WITH([dbfile], AC_HELP_STRING([--with-dbfile=path], [Pathname to the NSD database]), [dbfile=$withval]) AC_SUBST(dbfile) AC_DEFINE_UNQUOTED(DBFILE, ["`eval echo $dbfile`"], [Pathname to the NSD database]) if test -n "$dbfile"; then dbdir=`dirname $dbfile` fi AC_SUBST(dbdir) piddir=`dirname $pidfile` AC_SUBST(piddir) # # Determine the default directory for the zone files # zonesdir=$configdir AC_ARG_WITH([zonesdir], AC_HELP_STRING([--with-zonesdir=dir], [NSD default location for zone files]), [zonesdir=$withval]) AC_SUBST(zonesdir) AC_DEFINE_UNQUOTED(ZONESDIR, ["`eval echo $zonesdir`"], [NSD default location for zone files. Empty string or NULL to disable.]) # default xfrd file location. xfrdfile=${dbdir}/xfrd.state AC_ARG_WITH([xfrdfile], AC_HELP_STRING([--with-xfrdfile=path], [Pathname to the NSD xfrd zone timer state file]), [xfrdfile=$withval]) AC_DEFINE_UNQUOTED(XFRDFILE, ["`eval echo $xfrdfile`"], [Pathname to the NSD xfrd zone timer state file.]) AC_SUBST(xfrdfile) # default zonelist file location. zonelistfile=${dbdir}/zone.list AC_ARG_WITH([zonelistfile], AC_HELP_STRING([--with-zonelistfile=path], [Pathname to the NSD zone list file]), [zonelistfile=$withval]) AC_DEFINE_UNQUOTED(ZONELISTFILE, ["`eval echo $zonelistfile`"], [Pathname to the NSD zone list file.]) AC_SUBST(zonelistfile) # default xfr dir location. xfrdir="/tmp" AC_ARG_WITH([xfrdir], AC_HELP_STRING([--with-xfrdir=path], [Pathname to where the NSD transfer dir is created]), [xfrdir=$withval]) AC_DEFINE_UNQUOTED(XFRDIR, ["`eval echo $xfrdir`"], [Pathname to where the NSD transfer dir is created.]) AC_SUBST(xfrdir) # nsd sbin location. tmpinstantiate execprefix with defaults if not yet done. if test "x${exec_prefix}" = "xNONE"; then if test "x${prefix}" = "xNONE"; then exec_prefix="$ac_default_prefix" else exec_prefix="${prefix}"; fi nsd_start_path="`eval echo $sbindir`/nsd" exec_prefix="NONE" else nsd_start_path="`eval echo $sbindir`/nsd" fi AC_DEFINE_UNQUOTED(NSD_START_PATH, ["$nsd_start_path"], [Pathname to start nsd from nsd-control]) # # Determine default chroot directory # AC_ARG_WITH([chroot], AC_HELP_STRING([--with-chroot=dir], [NSD default chroot directory]), [ chrootdir=$withval AC_DEFINE_UNQUOTED(CHROOTDIR, ["`eval echo $chrootdir`"], [NSD default chroot directory]) ]) AC_SUBST(chrootdir) # # Determine the user name to drop privileges to # user=nsd AC_ARG_WITH([user], AC_HELP_STRING([--with-user=username], [User name or ID to answer the queries with]), [user=$withval]) AC_SUBST(user) AC_DEFINE_UNQUOTED(USER, ["$user"], [the user name to drop privileges to]) # Checks for programs. AC_PROG_AWK AC_PROG_CC AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_LEX AC_PROG_YACC if test "$LEX" != ":" -a "$LEX" != ""; then # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, # but later could define it as a macro and then we should not redefine it. AC_MSG_CHECKING(if lex defines yy_current_buffer) cat <conftest.lex %% EOF $LEX -i -t conftest.lex >> conftest.c if grep "^#define yy_current_buffer" conftest.c >/dev/null; then AC_DEFINE_UNQUOTED(LEX_DEFINES_YY_CURRENT_BUFFER, 1, [If flex defines yy_current_buffer as a macro]) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi rm -f conftest.lex conftest.c fi AC_DEFUN([AC_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute) AC_CACHE_VAL(ac_cv_c_format_attribute, [ac_cv_c_format_attribute=no AC_TRY_COMPILE( [#include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); ], [ f ("%s", "str"); ], [ac_cv_c_format_attribute="yes"], [ac_cv_c_format_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_format_attribute) if test $ac_cv_c_format_attribute = yes; then AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute]) fi ])dnl AC_DEFUN([AC_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute) AC_CACHE_VAL(ac_cv_c_unused_attribute, [ac_cv_c_unused_attribute=no AC_TRY_COMPILE( [#include void f (char *u __attribute__((unused))); ], [ f ("x"); ], [ac_cv_c_unused_attribute="yes"], [ac_cv_c_unused_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_unused_attribute) if test $ac_cv_c_unused_attribute = yes; then AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) fi ])dnl AC_DEFUN([CHECK_NORETURN_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "noreturn" attribute) AC_CACHE_VAL(ac_cv_c_noreturn_attribute, [ac_cv_c_noreturn_attribute=no AC_TRY_COMPILE( [ #include __attribute__((noreturn)) void f(int x) { printf("%d", x); } ], [ f(1); ], [ac_cv_c_noreturn_attribute="yes"], [ac_cv_c_noreturn_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_noreturn_attribute) if test $ac_cv_c_noreturn_attribute = yes; then AC_DEFINE(HAVE_ATTR_NORETURN, 1, [Whether the C compiler accepts the "noreturn" attribute]) AC_DEFINE(ATTR_NORETURN, [__attribute__((__noreturn__))], [apply the noreturn attribute to a function that exits the program]) fi ])dnl End of CHECK_NORETURN_ATTRIBUTE AC_DEFUN([CHECK_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ echo 'void f(){}' >conftest.c if test -z "`$CC -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* ]) if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $2 else AC_MSG_RESULT(no) : $3 fi ]) AC_DEFUN([AC_CHECK_CTIME_R], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether ctime_r works with two arguments) AC_CACHE_VAL(ac_cv_c_ctime_c, [ac_cv_c_ctime_c=no AC_TRY_COMPILE( [#include void testing (void) { time_t clock; char current_time[40]; ctime_r(&clock, current_time); }], [ testing(); ], [ac_cv_c_ctime_c="yes"], [ac_cv_c_ctime_c="no"]) ]) AC_MSG_RESULT($ac_cv_c_ctime_c) if test $ac_cv_c_ctime_c = no; then CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" fi ])dnl # Checks for typedefs, structures, and compiler characteristics. # allow user to override the -g -O2 flags. if test "x$CFLAGS" = "x" ; then ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"]) # we do not use O3 because it causes miscompilations. ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"]) ACX_CHECK_FLTO ACX_CHECK_PIE ACX_CHECK_RELRO_NOW fi AC_C_CONST AC_C_INLINE AC_TYPE_UID_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_OFF_T AC_CHECK_FORMAT_ATTRIBUTE AC_CHECK_UNUSED_ATTRIBUTE CHECK_NORETURN_ATTRIBUTE ACX_CHECK_MEMCMP_SIGNED AC_CHECK_CTIME_R # Checks for libraries. # Check for SSL, original taken from # http://www.gnu.org/software/ac-archive/htmldoc/check_ssl.html and # modified for NSD. AC_DEFUN([CHECK_SSL], [ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname], [enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr)]),[ ],[ withval="yes" ]) if test x_$withval != x_no; then AC_MSG_CHECKING(for SSL) if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes"; AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.]) if test x_$ssldir != x_/usr; then CPPFLAGS="$CPPFLAGS -I$ssldir/include"; fi break; fi done if test x_$found_ssl != x_yes; then AC_MSG_ERROR(Cannot find the SSL libraries in $withval) else AC_MSG_RESULT(found in $ssldir) HAVE_SSL=yes if test x_$ssldir != x_/usr; then LDFLAGS="$LDFLAGS -L$ssldir/lib"; fi if test x_$ssldir = x_/usr/sfw; then LDFLAGS="$LDFLAGS -R$ssldir/lib"; fi fi AC_SUBST(HAVE_SSL) fi ])dnl # check for libevent AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=pathname], [use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr or you can specify an explicit path), useful when the zone count is high.]), [ ],[ withval="yes" ]) if test x_$withval = x_yes -o x_$withval != x_no; then AC_MSG_CHECKING(for libevent) if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr" fi for dir in $withval; do thedir="$dir" if test -f "$dir/include/event.h" -o -f "$dir/include/event2/event.h"; then found_libevent="yes" dnl assume /usr is in default path. if test "$thedir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$thedir/include" fi break; fi done if test x_$found_libevent != x_yes; then if test -f "$dir/event.h" -a \( -f "$dir/libevent.la" -o -f "$dir/libev.la" \) ; then # libevent source directory AC_MSG_RESULT(found in $thedir) CPPFLAGS="$CPPFLAGS -I$thedir -I$thedir/include" # remove evdns from linking ev_files_o=`ls $thedir/*.o | grep -v evdns\.o | grep -v bufferevent_openssl\.o` cp $ev_files_o . LDFLAGS="$ev_files_o $LDFLAGS -lm" else AC_MSG_ERROR([Cannot find the libevent library. You can restart ./configure --with-libevent=no to use a builtin alternative.]) fi else AC_MSG_RESULT(found in $thedir) dnl if event2 exists and no event lib in dir itself, use subdir if test ! -f $thedir/lib/libevent.a -a ! -f $thedir/lib/libevent.so -a -d "$thedir/lib/event2"; then LDFLAGS="$LDFLAGS -L$thedir/lib/event2" ACX_RUNTIME_PATH_ADD([$thedir/lib/event2]) else dnl assume /usr is in default path, do not add "". if test "$thedir" != "/usr" -a "$thedir" != ""; then LDFLAGS="$LDFLAGS -L$thedir/lib" ACX_RUNTIME_PATH_ADD([$thedir/lib]) fi fi fi # check for library used by libevent after 1.3c AC_SEARCH_LIBS([clock_gettime], [rt]) # is the event.h header libev or libevent? AC_CHECK_HEADERS([event.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_DECL(EV_VERSION_MAJOR, [ AC_SEARCH_LIBS(event_set, [ev]) ],[ AC_SEARCH_LIBS(event_set, [event]) ],[AC_INCLUDES_DEFAULT #include ]) AC_CHECK_FUNCS([event_base_free]) # only in libevent 1.2 and later AC_CHECK_FUNCS([event_base_once]) # only in libevent 1.4.1 and later AC_CHECK_FUNCS([event_base_new]) # only in libevent 1.4.1 and later AC_CHECK_FUNCS([event_base_get_method]) # only in libevent 1.4.3 and later AC_CHECK_FUNCS([ev_loop]) # only in libev. (tested on 3.51) AC_CHECK_FUNCS([ev_default_loop]) # only in libev. (tested on 4.00) else AC_DEFINE(USE_MINI_EVENT, 1, [Define if you want to use internal select based events]) fi # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([time.h arpa/inet.h signal.h string.h strings.h fcntl.h limits.h netinet/in.h netinet/tcp.h stddef.h sys/param.h sys/socket.h sys/un.h syslog.h unistd.h sys/select.h stdarg.h stdint.h netdb.h sys/bitypes.h tcpd.h glob.h grp.h endian.h]) AC_DEFUN([CHECK_VALIST_DEF], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for double definition of struct va_list) AC_CACHE_VAL(ac_cv_c_va_list_def, [ cat >conftest.c < #include int foo(void); EOF if test -z "`$CC -Werror -D_XOPEN_SOURCE=600 -c conftest.c 2>&1`"; then eval "ac_cv_c_va_list_def=no" else eval "ac_cv_c_va_list_def=yes" fi rm -f conftest* ]) if test $ac_cv_c_va_list_def = yes; then AC_MSG_RESULT(yes) : AC_DEFINE_UNQUOTED([HAVE_VA_LIST_DOUBLE_DEF], [], [Define this if you have double va_list definitions.]) else AC_MSG_RESULT(no) : fi ]) CHECK_VALIST_DEF AC_DEFUN([AC_CHECK_STRPTIME], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether strptime needs defines) AC_CACHE_VAL(ac_cv_c_strptime_needs_defs, [ cat >conftest.c < int testing (void) { struct tm t; const char *timestr="201201"; return strptime(timestr, "%Y%m", &t) != 0; } EOF if test -z "`$CC -Wall -Werror -c conftest.c 2>&1`"; then eval "ac_cv_c_strptime_needs_defs=no" else eval "ac_cv_c_strptime_needs_defs=yes" fi rm -f conftest* ]) AC_MSG_RESULT($ac_cv_c_strptime_needs_defs) if test $ac_cv_c_strptime_needs_defs = yes; then AC_DEFINE_UNQUOTED([STRPTIME_NEEDS_DEFINES], 1, [strptime is available from time.h with some defines.]) fi ])dnl AC_CHECK_STRPTIME # check wether strptime also works AC_DEFUN([AC_CHECK_STRPTIME_WORKS], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether strptime works) if test c${cross_compiling} = cno; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #define _XOPEN_SOURCE 600 #include int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } ]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"]) else eval "ac_cv_c_strptime_works=maybe" fi AC_MSG_RESULT($ac_cv_c_strptime_works) if test $ac_cv_c_strptime_works = no; then AC_LIBOBJ(strptime) else AC_DEFINE_UNQUOTED([STRPTIME_WORKS], 1, [use default strptime.]) fi ])dnl AC_SEARCH_LIBS(inet_pton, [nsl]) AC_SEARCH_LIBS(socket, [socket]) AC_CHECK_STRPTIME_WORKS ACX_CHECK_NONBLOCKING_BROKEN ACX_MKDIR_ONE_ARG # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." else CPPFLAGS="-I." fi if test "$srcdir" != "."; then CPPFLAGS="$CPPFLAGS -I$srcdir" if test -f $srcdir/config.h; then AC_ERROR([$srcdir/config.h is in the way, please remove it]) fi fi dnl LIBGTOP_CHECK_TYPE dnl Stolen from Gnome's anjuta dnl Improved version of AC_CHECK_TYPE which takes into account dnl that we need to #include some other header files on some dnl systems to get some types. dnl AC_LIBGTOP_CHECK_TYPE(TYPE, DEFAULT) AC_DEFUN([AC_LIBGTOP_CHECK_TYPE], [AC_REQUIRE([AC_HEADER_STDC])dnl AC_MSG_CHECKING(for $1) AC_CACHE_VAL(ac_cv_type_$1, [AC_EGREP_CPP(dnl changequote(<<,>>)dnl <<(^|[^a-zA-Z_0-9])$1[^a-zA-Z_0-9]>>dnl changequote([,]), [ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif ], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl AC_MSG_RESULT($ac_cv_type_$1) if test $ac_cv_type_$1 = no; then AC_DEFINE($1, $2, Define "$1" to "$2" if "$1" is missing) fi ]) AC_LIBGTOP_CHECK_TYPE(int8_t, char) AC_LIBGTOP_CHECK_TYPE(int16_t, short) AC_LIBGTOP_CHECK_TYPE(int32_t, int) AC_LIBGTOP_CHECK_TYPE(int64_t, long long) AC_LIBGTOP_CHECK_TYPE(uint8_t, unsigned char) AC_LIBGTOP_CHECK_TYPE(uint16_t, unsigned short) AC_LIBGTOP_CHECK_TYPE(uint32_t, unsigned int) AC_LIBGTOP_CHECK_TYPE(uint64_t, unsigned long long) AC_LIBGTOP_CHECK_TYPE(socklen_t, int) AC_LIBGTOP_CHECK_TYPE(sig_atomic_t, int) AC_LIBGTOP_CHECK_TYPE(ssize_t, int) AC_LIBGTOP_CHECK_TYPE(suseconds_t, time_t) AC_CHECK_TYPE(in_addr_t, [], [AC_DEFINE([in_addr_t], [uint32_t], [in_addr_t])], [ #if HAVE_SYS_TYPES_H # include #endif #if HAVE_NETINET_IN_H # include #endif]) ACX_CHECK_SS_FAMILY AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec]) AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_UN_H #include #endif ]) # Checks for library functions. AC_FUNC_CHOWN AC_FUNC_FORK AC_FUNC_MALLOC AC_TYPE_SIGNAL AC_FUNC_FSEEKO AC_SYS_LARGEFILE AC_CHECK_SIZEOF(void*) AC_CHECK_SIZEOF(off_t) AC_CHECK_FUNCS([arc4random arc4random_uniform]) AC_CHECK_FUNCS([tzset alarm chroot dup2 endpwent gethostname memset memcpy pwrite socket strcasecmp strchr strdup strerror strncasecmp strtol writev getaddrinfo getnameinfo freeaddrinfo gai_strerror sigaction sigprocmask strptime strftime localtime_r setusercontext glob initgroups setresuid setreuid setresgid setregid getpwnam mmap ppoll clock_gettime accept4]) AC_ARG_ENABLE(recvmmsg, AC_HELP_STRING([--enable-recvmmsg], [Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems for IPv6])) case "$enable_recvmmsg" in yes) AC_CHECK_FUNC([recvmmsg], [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = recvmmsg(s, 0, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } ]])], [ AC_DEFINE([HAVE_RECVMMSG], [1], [Define if recvmmsg is implemented])], [ ], [ AC_DEFINE([HAVE_RECVMMSG], [1], [Define if recvmmsg exists])] )]) AC_CHECK_FUNC([sendmmsg], [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = sendmmsg(s, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } ]])], [ AC_DEFINE([HAVE_SENDMMSG], [1], [Define if sendmmsg is implemented])], [ ], [ AC_DEFINE([HAVE_SENDMMSG], [1], [Define if sendmmsg exists])] )]) ;; no|*) ;; esac # check if setreuid en setregid fail, on MacOSX10.4(darwin8). if echo $target_os | grep darwin8 > /dev/null; then AC_DEFINE(DARWIN_BROKEN_SETREUID, 1, [Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work]) fi # # Checking for missing functions we can replace # AC_REPLACE_FUNCS(basename) AC_REPLACE_FUNCS(inet_aton) AC_REPLACE_FUNCS(inet_pton) AC_REPLACE_FUNCS(inet_ntop) AC_REPLACE_FUNCS(snprintf) AC_REPLACE_FUNCS(strlcat) AC_REPLACE_FUNCS(strlcpy) AC_REPLACE_FUNCS(strptime) AC_REPLACE_FUNCS(b64_pton) AC_REPLACE_FUNCS(b64_ntop) AC_REPLACE_FUNCS(pselect) AC_REPLACE_FUNCS(memmove) AC_REPLACE_FUNCS(reallocarray) AC_MSG_CHECKING(for pselect prototype in sys/select.h) AC_EGREP_HEADER([[^a-zA-Z_]*pselect[^a-zA-Z_]], sys/select.h, AC_DEFINE(HAVE_PSELECT_PROTO, 1, [if sys/select.h provides pselect prototype]) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_MSG_CHECKING(for ctime_r prototype in time.h) AC_EGREP_HEADER([[^a-zA-Z_]*ctime_r[^a-zA-Z_]], time.h, AC_DEFINE(HAVE_CTIME_R_PROTO, 1, [if time.h provides ctime_r prototype]) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) AC_CHECK_TYPE([struct timespec], AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1, [If time.h has a struct timespec (for pselect).]), [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_TIME_H #include #endif ]) dnl dnl Some random defines's dnl AC_DEFINE_UNQUOTED([IDENTITY], ["unidentified server"], [Define to the default nsd identity.]) AC_DEFINE_UNQUOTED([VERSION], [PACKAGE_STRING], [Define to the NSD version to answer version.server query.]) AC_DEFINE_UNQUOTED([TCP_BACKLOG], [256], [Define to the backlog to be used with listen.]) AC_DEFINE_UNQUOTED([TCP_PORT], ["53"], [Define to the default tcp port.]) AC_DEFINE_UNQUOTED([TCP_MAX_MESSAGE_LEN], [65535], [Define to the default maximum message length.]) AC_DEFINE_UNQUOTED([UDP_PORT], ["53"], [Define to the default udp port.]) AC_DEFINE_UNQUOTED([UDP_MAX_MESSAGE_LEN], [512], [Define to the default maximum udp message length.]) AC_DEFINE_UNQUOTED([EDNS_MAX_MESSAGE_LEN], [4096], [Define to the default maximum message length with EDNS.]) AC_DEFINE_UNQUOTED([MAXSYSLOGMSGLEN], [512], [Define to the maximum message length to pass to syslog.]) AC_DEFINE_UNQUOTED([NSD_CONTROL_PORT], [8952], [Define to the default nsd-control port.]) AC_DEFINE_UNQUOTED([NSD_CONTROL_VERSION], [1], [Define to nsd-control proto version.]) dnl dnl Determine the syslog facility to use dnl facility=LOG_DAEMON AC_ARG_WITH([facility], AC_HELP_STRING([--with-facility=name], [Syslog default facility (LOG_DAEMON)]), [facility=$withval]) AC_DEFINE_UNQUOTED([FACILITY], $facility, [Define to the default facility for syslog.]) dnl dnl Determine the default tcp timeout dnl tcp_timeout=120 AC_ARG_WITH([tcp_timeout], AC_HELP_STRING([--with-tcp-timeout=number], [Limit the default tcp timeout]), [tcp_timeout=$withval]) AC_DEFINE_UNQUOTED([TCP_TIMEOUT], $tcp_timeout, [Define to the default tcp timeout.]) dnl dnl Features dnl AC_ARG_ENABLE(root-server, AC_HELP_STRING([--enable-root-server], [Configure NSD as a root server])) case "$enable_root_server" in yes) AC_DEFINE_UNQUOTED([ROOT_SERVER], [], [Define this to configure as a root server.]) ;; no|*) ;; esac AC_ARG_ENABLE(ipv6, AC_HELP_STRING([--disable-ipv6], [Disables IPv6 support])) case "$enable_ipv6" in no) ;; yes|*) AC_DEFINE_UNQUOTED([INET6], [], [Define this to enable IPv6 support.]) ;; esac AC_ARG_ENABLE(bind8-stats, AC_HELP_STRING([--enable-bind8-stats], [Enables BIND8 like NSTATS & XSTATS and statistics in nsd-control])) case "$enable_bind8_stats" in yes|'') AC_DEFINE_UNQUOTED([BIND8_STATS], [], [Define this to enable BIND8 like NSTATS & XSTATS.]) ;; no|*) ;; esac AC_ARG_ENABLE(zone-stats, AC_HELP_STRING([--enable-zone-stats], [Enable per-zone statistics gathering (needs --enable-bind8-stats)])) case "$enable_zone_stats" in yes) AC_DEFINE_UNQUOTED([USE_ZONE_STATS], [], [Define this to enable per-zone statistics gathering.]) AC_DEFINE_UNQUOTED([BIND8_STATS], [], [Define this to enable BIND8 like NSTATS & XSTATS.]) ;; no|''|*) ;; esac AC_ARG_ENABLE(checking, AC_HELP_STRING([--enable-checking], [Enable internal runtime checks])) case "$enable_checking" in yes) CHECK_COMPILER_FLAG(W, [ CFLAGS="$CFLAGS -W" ]) CHECK_COMPILER_FLAG(Wall, [ CFLAGS="$CFLAGS -Wall" ]) CHECK_COMPILER_FLAG(Wextra, [ CFLAGS="$CFLAGS -Wextra" ]) CHECK_COMPILER_FLAG(Wdeclaration-after-statement, [ CFLAGS="$CFLAGS -Wdeclaration-after-statement" ]) ;; no|*) AC_DEFINE([NDEBUG], [], [Undefine this to enable internal runtime checks.]) ;; esac AC_ARG_ENABLE(memclean, AC_HELP_STRING([--enable-memclean], [Cleanup memory (at exit) for eg. valgrind, memcheck])) if test "$enable_memclean" = "yes"; then AC_DEFINE_UNQUOTED([MEMCLEAN], [1], [Define this to cleanup memory at exit (eg. for valgrind, etc.)]) fi AC_ARG_ENABLE(ratelimit, AC_HELP_STRING([--enable-ratelimit], [Enable rate limiting])) case "$enable_ratelimit" in yes) AC_DEFINE_UNQUOTED([RATELIMIT], [], [Define this to enable rate limiting.]) dnl causes awk to not match the exclusion start marker. ratelimit="xx" ;; no|*) ratelimit="" ;; esac AC_SUBST(ratelimit) AC_ARG_ENABLE(ratelimit-default-is-off, AC_HELP_STRING([--enable-ratelimit-default-is-off], [Enable this to set default of ratelimit to off (enable in nsd.conf), otherwise ratelimit is enabled by default if --enable-ratelimit is enabled])) case "$enable_ratelimit_default_is_off" in yes) AC_DEFINE_UNQUOTED([RATELIMIT_DEFAULT_OFF], [], [Define this to set ratelimit to off by default.]) ratelimit_default="off" ;; no|*) ratelimit_default="on" ;; esac AC_SUBST(ratelimit_default) # we need SSL for TSIG (and maybe also for NSEC3). CHECK_SSL if test x$HAVE_SSL = x"yes"; then ACX_LIB_SSL # Check for -pthread BAKLIBS="$LIBS" LIBS="-lcrypto $LIBS" AC_TRY_LINK([], [ int HMAC_Update(void); (void)HMAC_Update(); ], [],[ dnl so link fails for HMAC_Update, try with -pthread. BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pthread" AC_MSG_CHECKING([if libcrypto needs -pthread]) AC_TRY_LINK_FUNC([HMAC_Update], [ AC_MSG_RESULT([yes]) ] , [ AC_MSG_RESULT([no]) dnl restore the nonpthread value CFLAGS="$BAKCFLAGS" ]) ]) LIBS="$BAKLIBS" if test -n "$ssldir"; then AC_CHECK_LIB(crypto, HMAC_Update,, [ AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) ]) fi SSL_LIBS="-lssl" AC_SUBST(SSL_LIBS) AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto]) BAKLIBS="$LIBS" LIBS="-lssl $LIBS" AC_CHECK_FUNCS([OPENSSL_init_ssl]) LIBS="$BAKLIBS" else AC_MSG_WARN([No SSL, therefore remote-control is disabled]) fi AC_ARG_ENABLE(nsec3, AC_HELP_STRING([--disable-nsec3], [Disable NSEC3 support])) case "$enable_nsec3" in no) ;; yes) AC_DEFINE_UNQUOTED([NSEC3], [], [Define this to enable NSEC3 support.]) ;; *) if test x$HAVE_SSL = x"yes"; then AC_DEFINE_UNQUOTED([NSEC3], [], [Define this to enable NSEC3 support.]) else AC_MSG_WARN([No SSL, therefore NSEC3 is disabled]) fi ;; esac AC_ARG_ENABLE(minimal-responses, AC_HELP_STRING([--disable-minimal-responses], [Disable response minimization. More truncation.])) case "$enable_minimal_responses" in no) ;; yes|*) AC_DEFINE_UNQUOTED([MINIMAL_RESPONSES], [], [Define this to enable response minimalization to reduce truncation.]) ;; esac AC_ARG_ENABLE(mmap, AC_HELP_STRING([--enable-mmap], [Use mmap instead of malloc. Experimental.])) case "$enable_mmap" in yes) AC_CHECK_HEADERS([sys/mman.h]) AC_LIBGTOP_CHECK_TYPE(uintptr_t, void*) AC_CHECK_FUNCS([mmap munmap]) AC_DEFINE_UNQUOTED([USE_MMAP_ALLOC], [], [Define this to enable mmap instead of malloc. Experimental.]) ;; no|*) ;; esac AC_ARG_ENABLE(radix-tree, AC_HELP_STRING([--disable-radix-tree], [You can disable the radix tree and use the red-black tree for the main lookups, the red-black tree uses less memory, but uses some more CPU.])) case "$enable_radix_tree" in no) ;; yes|*) AC_DEFINE_UNQUOTED([USE_RADIX_TREE], [], [Define this to configure to use the radix tree.]) ;; esac AC_ARG_ENABLE(packed, AC_HELP_STRING([--enable-packed], [Enable packed structure alignment, uses less memory, but unaligned reads.])) case "$enable_packed" in yes) AC_DEFINE_UNQUOTED([PACKED_STRUCTS], [], [Define this to use packed structure alignment.]) ACX_CHECK_COMPILER_FLAG(Wno-address-of-packed-member, [CFLAGS="$CFLAGS -Wno-address-of-packed-member"]) ;; no|*) ;; esac # check for dnstap if requested dt_DNSTAP([${localstatedir}/run/nsd-dnstap.sock], [ AC_DEFINE([USE_DNSTAP], [1], [Define to 1 to enable dnstap support]) AC_SUBST([ENABLE_DNSTAP], [1]) AC_SUBST([opt_dnstap_socket_path]) ACX_ESCAPE_BACKSLASH($opt_dnstap_socket_path, hdr_dnstap_socket_path) AC_DEFINE_UNQUOTED(DNSTAP_SOCKET_PATH, ["$hdr_dnstap_socket_path"], [default dnstap socket path]) AC_SUBST([DNSTAP_SRC], ["dnstap/dnstap.c dnstap/dnstap.pb-c.c dnstap/dnstap_collector.c"]) AC_SUBST([DNSTAP_OBJ], ["dnstap.o dnstap_collector.o dnstap.pb-c.o"]) dnstap_config="dnstap/dnstap_config.h" ], [ AC_SUBST([ENABLE_DNSTAP], [0]) ] ) # Include systemd.m4 - begin sinclude(systemd.m4) # Include systemd.m4 - end AH_BOTTOM([ /* define before includes as it specifies what standard to use. */ #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \ || !defined (HAVE_CTIME_R_PROTO) \ || defined (STRPTIME_NEEDS_DEFINES) # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 # endif # ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 200112 # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE 1 # endif # ifndef _DEFAULT_SOURCE # define _DEFAULT_SOURCE 1 # endif # ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 # endif # ifndef _STDC_C99 # define _STDC_C99 1 # endif # ifndef _ALL_SOURCE # define _ALL_SOURCE 1 # endif #endif ]) AH_BOTTOM([ #ifdef HAVE_VA_LIST_DOUBLE_DEF /* workaround double va_list definition on some platforms */ # ifndef _VA_LIST_DEFINED # define _VA_LIST_DEFINED # endif #endif ]) AH_BOTTOM([ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif ]) AH_BOTTOM([ #ifdef HAVE_ATTR_FORMAT #define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ #define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ #if defined(__cplusplus) #define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) #define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ #define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ ]) AH_BOTTOM([ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ #ifndef AF_INET6 #define AF_INET6 28 #endif /* AF_INET6 */ ]) if test $ac_cv_func_getaddrinfo = no; then AC_LIBOBJ([fake-rfc2553]) fi AH_BOTTOM([ /* maximum nesting of included files */ #define MAXINCLUDES 10 ]) AH_BOTTOM([ #ifndef HAVE_B64_NTOP int b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize); #endif /* !HAVE_B64_NTOP */ #ifndef HAVE_B64_PTON int b64_pton(char const *src, uint8_t *target, size_t targsize); #endif /* !HAVE_B64_PTON */ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ #ifndef HAVE_SNPRINTF #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ #ifndef HAVE_INET_PTON int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *addr); #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_REALLOCARRAY void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif #ifndef HAVE_STRPTIME #define HAVE_STRPTIME 1 char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif ]) AH_BOTTOM( AHX_MEMCMP_BROKEN(nsd) AHX_CONFIG_MAXHOSTNAMELEN ) AH_BOTTOM([ /* provide timespec def if not available */ #ifndef CONFIG_DEFINES #define CONFIG_DEFINES #ifndef HAVE_STRUCT_TIMESPEC #ifndef __timespec_defined #define __timespec_defined 1 struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; #endif /* !__timespec_defined */ #endif /* !HAVE_STRUCT_TIMESPEC */ #endif /* !CONFIG_DEFINES */ #ifdef PACKED_STRUCTS #define ATTR_PACKED __attribute__((packed)) #else #define ATTR_PACKED #endif ]) # big fat warning if test "$enable_checking" = "yes"; then echo "************************************************" echo "* You have activated \"--enable-checking\" *" echo "* *" echo "* This will instruct NSD to be stricter *" echo "* when validating its input. This could lead *" echo "* to a reduced service level. *" echo "* *" echo "************************************************" fi AC_CONFIG_FILES([Makefile $dnstap_config]) AC_OUTPUT nsd-4.1.26/nsd-control-setup.sh.in0000775000175000017500000001174412500331024016367 0ustar wouterwouter#!/bin/sh # # nsd-control-setup.sh - set up SSL certificates for nsd-control # # Copyright (c) 2011, NLnet Labs. All rights reserved. # # This software is open source. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of the NLNET LABS nor the names of its contributors may # be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # settings: # directory for files DESTDIR=@configdir@ # issuer and subject name for certificates SERVERNAME=nsd CLIENTNAME=nsd-control # validity period for certificates DAYS=7200 # size of keys in bits BITS=3072 # hash algorithm HASH=sha256 # base name for nsd server keys SVR_BASE=nsd_server # base name for nsd-control keys CTL_BASE=nsd_control # we want -rw-r--- access (say you run this as root: grp=yes (server), all=no). umask 0026 # end of options # functions: error ( ) { echo "$0 fatal error: $1" exit 1 } # check arguments: while test $# -ne 0; do case $1 in -d) if test $# -eq 1; then error "need argument for -d"; fi DESTDIR="$2" shift ;; *) echo "nsd-control-setup.sh - setup SSL keys for nsd-control" echo " -d dir use directory to store keys and certificates." echo " default: $DESTDIR" exit 1 ;; esac shift done # go!: echo "setup in directory $DESTDIR" cd "$DESTDIR" || error "could not cd to $DESTDIR" # create certificate keys; do not recreate if they already exist. if test -f $SVR_BASE.key; then echo "$SVR_BASE.key exists" else echo "generating $SVR_BASE.key" openssl genrsa -out $SVR_BASE.key $BITS || error "could not genrsa" fi if test -f $CTL_BASE.key; then echo "$CTL_BASE.key exists" else echo "generating $CTL_BASE.key" openssl genrsa -out $CTL_BASE.key $BITS || error "could not genrsa" fi # create self-signed cert for server cat >request.cfg <request.cfg <2G files. # ACX_CHECK_GETADDRINFO_WITH_INCLUDES - find getaddrinfo, portably. # ACX_FUNC_DEPRECATED - see if func is deprecated. # ACX_CHECK_NONBLOCKING_BROKEN - see if nonblocking sockets really work. # ACX_MKDIR_ONE_ARG - determine mkdir(2) number of arguments. # ACX_FUNC_IOCTLSOCKET - find ioctlsocket, portably. # ACX_FUNC_MALLOC - check malloc, define replacement . # AHX_CONFIG_FORMAT_ATTRIBUTE - config.h text for format. # AHX_CONFIG_UNUSED_ATTRIBUTE - config.h text for unused. # AHX_CONFIG_FSEEKO - define fseeko, ftello fallback. # AHX_CONFIG_RAND_MAX - define RAND_MAX if needed. # AHX_CONFIG_MAXHOSTNAMELEN - define MAXHOSTNAMELEN if needed. # AHX_CONFIG_IPV6_MIN_MTU - define IPV6_MIN_MTU if needed. # AHX_CONFIG_SNPRINTF - snprintf compat prototype # AHX_CONFIG_INET_PTON - inet_pton compat prototype # AHX_CONFIG_INET_NTOP - inet_ntop compat prototype # AHX_CONFIG_INET_ATON - inet_aton compat prototype # AHX_CONFIG_MEMMOVE - memmove compat prototype # AHX_CONFIG_STRLCAT - strlcat compat prototype # AHX_CONFIG_STRLCPY - strlcpy compat prototype # AHX_CONFIG_GMTIME_R - gmtime_r compat prototype # AHX_CONFIG_W32_SLEEP - w32 compat for sleep # AHX_CONFIG_W32_USLEEP - w32 compat for usleep # AHX_CONFIG_W32_RANDOM - w32 compat for random # AHX_CONFIG_W32_SRANDOM - w32 compat for srandom # AHX_CONFIG_W32_FD_SET_T - w32 detection of FD_SET_T. # ACX_CFLAGS_STRIP - strip one flag from CFLAGS # ACX_STRIP_EXT_FLAGS - strip extension flags from CFLAGS # AHX_CONFIG_FLAG_OMITTED - define omitted flag # AHX_CONFIG_FLAG_EXT - define omitted extension flag # AHX_CONFIG_EXT_FLAGS - define the stripped extension flags # ACX_CHECK_MEMCMP_SIGNED - check if memcmp uses signed characters. # AHX_MEMCMP_BROKEN - replace memcmp func for CHECK_MEMCMP_SIGNED. # ACX_CHECK_SS_FAMILY - check for sockaddr_storage.ss_family # ACX_CHECK_PIE - add --enable-pie option and check if works # ACX_CHECK_RELRO_NOW - add --enable-relro-now option and check it # dnl Escape backslashes as \\, for C:\ paths, for the C preprocessor defines. dnl for example, ACX_ESCAPE_BACKSLASH($from_var, to_var) dnl $1: the text to change. dnl $2: the result. AC_DEFUN([ACX_ESCAPE_BACKSLASH], [$2="`echo $1 | sed -e 's/\\\\/\\\\\\\\/g'`" ]) dnl Calculate comma separated windows-resource numbers from package version. dnl Picks the first three(,0) or four numbers out of the name. dnl $1: variable for the result AC_DEFUN([ACX_RSRC_VERSION], [$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9]*$/\1,\2,\3,0/' `] ]) dnl Routine to help check for compiler flags. dnl Checks if the compiler will accept the flag. dnl $1: the flag without a - in front, so g to check -g. dnl $2: executed if yes dnl $3: executed if no AC_DEFUN([ACX_CHECK_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c ]) if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $2 else AC_MSG_RESULT(no) : $3 fi ]) dnl setup flags for ACX_CHECK_COMPILER_FLAG_NEEDED dnl ERRFLAG: result, compiler flag to turn warnings into errors AC_DEFUN([ACX_CHECK_ERROR_FLAGS], [ ACX_CHECK_COMPILER_FLAG(Werror, [ERRFLAG="-Werror"], [ERRFLAG="-errwarn"]) ACX_CHECK_COMPILER_FLAG(Wall, [ERRFLAG="$ERRFLAG -Wall"], [ERRFLAG="$ERRFLAG -errfmt"]) ]) dnl Routine to help check for needed compiler flags. dnl $1: flags for CC dnl $2: the includes and code dnl $3: if the given code only compiles with the flag, execute argument 3 dnl $4: if the given code compiles without the flag, execute argument 4 dnl $5: with and without flag the compile fails, execute argument 5. AC_DEFUN([ACX_CHECK_COMPILER_FLAG_NEEDED], [ AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([ACX_CHECK_ERROR_FLAGS]) AC_MSG_CHECKING(whether we need $1 as a flag for $CC) cache=AS_TR_SH($1) dnl cache=`echo $1 | sed 'y%.=/+- %___p__%'` AC_CACHE_VAL(cv_prog_cc_flag_needed_$cache, [ echo '$2' > conftest.c echo 'void f(){}' >>conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS $ERRFLAG -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_needed_$cache=no" else [ if test -z "`$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_needed_$cache=yes" else eval "cv_prog_cc_flag_needed_$cache=fail" #echo 'Test with flag fails too!' #cat conftest.c #echo "$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1" #echo `$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1` #exit 1 fi ] fi rm -f conftest conftest.c conftest.o ]) if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then AC_MSG_RESULT(yes) : $3 else if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = no"; then AC_MSG_RESULT(no) #echo 'Test with flag is no!' #cat conftest.c #echo "$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1" #echo `$CC $CPPFLAGS $CFLAGS $1 $ERRFLAG -c conftest.c 2>&1` #exit 1 : $4 else AC_MSG_RESULT(failed) : $5 fi fi ]) dnl Check for CC dependency flag dnl DEPFLAG: set to flag that generates dependencies. AC_DEFUN([ACX_DEPFLAG], [ AC_MSG_CHECKING([$CC dependency flag]) echo 'void f(){}' >conftest.c if test "`$CC -MM conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-MM" else if test "`$CC -xM1 conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-xM1" else DEPFLAG="-MM" # dunno do something fi fi AC_MSG_RESULT($DEPFLAG) rm -f conftest.c AC_SUBST(DEPFLAG) ]) dnl Determine flags that gives POSIX and BSD functionality. dnl CFLAGS is modified for the result. AC_DEFUN([ACX_DETERMINE_EXT_FLAGS_UNBOUND], [ ACX_CHECK_COMPILER_FLAG(std=c99, [C99FLAG="-std=c99"]) ACX_CHECK_COMPILER_FLAG(xc99, [C99FLAG="-xc99"]) AC_CHECK_HEADERS([getopt.h time.h],,, [AC_INCLUDES_DEFAULT]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #include #ifdef HAVE_GETOPT_H #include #endif int test() { int a; char **opts = NULL; struct timeval tv; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; struct msghdr msg; msg.msg_control = 0; t = ctime_r(&time, buf); tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); str = gai_strerror(0); if(str && t && tv.tv_usec && msg.msg_control) a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #include #ifdef HAVE_GETOPT_H #include #endif int test() { int a; char **opts = NULL; struct timeval tv; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; struct msghdr msg; msg.msg_control = 0; t = ctime_r(&time, buf); tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); str = gai_strerror(0); if(str && t && tv.tv_usec && msg.msg_control) a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG, [ #include #include int test() { int a = 0; return a; } ], [CFLAGS="$CFLAGS $C99FLAG"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_BSD_SOURCE -D_DEFAULT_SOURCE, [ #include int test() { int a; a = isascii(32); return a; } ], [CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE, [ #include int test() { struct in6_pktinfo inf; int a = (int)sizeof(inf); return a; } ], [CFLAGS="$CFLAGS -D_GNU_SOURCE"]) # check again for GNU_SOURCE for setresgid. May fail if setresgid # is not available at all. -D_FRSRESGID is to make this check unique. # otherwise we would get the previous cached result. ACX_CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE -D_FRSRESGID, [ #include int test() { int a = setresgid(0,0,0); a = setresuid(0,0,0); return a; } ], [CFLAGS="$CFLAGS -D_GNU_SOURCE"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D_POSIX_C_SOURCE=200112, [ #include "confdefs.h" #ifdef HAVE_TIME_H #include #endif #include int test() { int a = 0; char *t; time_t time = 0; char *buf = NULL; const char* str = NULL; t = ctime_r(&time, buf); str = gai_strerror(0); if(t && str) a = 0; return a; } ], [CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112"]) ACX_CHECK_COMPILER_FLAG_NEEDED(-D__EXTENSIONS__, [ #include "confdefs.h" #include #include #include #ifdef HAVE_TIME_H #include #endif #include #ifdef HAVE_GETOPT_H #include #endif int test() { int a; char **opts = NULL; struct timeval tv; tv.tv_usec = 10; srandom(32); a = getopt(2, opts, "a"); a = isascii(32); if(tv.tv_usec) a = 0; return a; } ], [CFLAGS="$CFLAGS -D__EXTENSIONS__"]) ])dnl End of ACX_DETERMINE_EXT_FLAGS_UNBOUND dnl Check if CC supports -flto. dnl in a way that supports clang and suncc (that flag does something else, dnl but fails to link). It sets it in CFLAGS if it works. AC_DEFUN([ACX_CHECK_FLTO], [ AC_ARG_ENABLE([flto], AS_HELP_STRING([--disable-flto], [Disable link-time optimization (gcc specific option)])) AS_IF([test "x$enable_flto" != "xno"], [ AC_MSG_CHECKING([if $CC supports -flto]) BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -flto" AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ if $CC $CFLAGS -o conftest conftest.c 2>&1 | $GREP -e "warning: no debug symbols in executable" -e "warning: object" >/dev/null; then CFLAGS="$BAKCFLAGS" AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi rm -f conftest conftest.c conftest.o ], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) ]) ]) dnl Check the printf-format attribute (if any) dnl result in HAVE_ATTR_FORMAT. dnl Make sure you also include the AHX_CONFIG_FORMAT_ATTRIBUTE. AC_DEFUN([ACX_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute) AC_CACHE_VAL(ac_cv_c_format_attribute, [ac_cv_c_format_attribute=no AC_TRY_COMPILE( [#include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); ], [ f ("%s", "str"); ], [ac_cv_c_format_attribute="yes"], [ac_cv_c_format_attribute="no"]) ]) AC_MSG_RESULT($ac_cv_c_format_attribute) if test $ac_cv_c_format_attribute = yes; then AC_DEFINE(HAVE_ATTR_FORMAT, 1, [Whether the C compiler accepts the "format" attribute]) fi ])dnl End of ACX_CHECK_FORMAT_ATTRIBUTE dnl Setup ATTR_FORMAT config.h parts. dnl make sure you call ACX_CHECK_FORMAT_ATTRIBUTE also. AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE], [ #ifdef HAVE_ATTR_FORMAT # define ATTR_FORMAT(archetype, string_index, first_to_check) \ __attribute__ ((format (archetype, string_index, first_to_check))) #else /* !HAVE_ATTR_FORMAT */ # define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */ #endif /* !HAVE_ATTR_FORMAT */ ]) dnl Check how to mark function arguments as unused. dnl result in HAVE_ATTR_UNUSED. dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also. AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute) AC_CACHE_VAL(ac_cv_c_unused_attribute, [ac_cv_c_unused_attribute=no AC_TRY_COMPILE( [#include void f (char *u __attribute__((unused))); ], [ f ("x"); ], [ac_cv_c_unused_attribute="yes"], [ac_cv_c_unused_attribute="no"]) ]) dnl Setup ATTR_UNUSED config.h parts. dnl make sure you call ACX_CHECK_UNUSED_ATTRIBUTE also. AC_DEFUN([AHX_CONFIG_UNUSED_ATTRIBUTE], [ #if defined(DOXYGEN) # define ATTR_UNUSED(x) x #elif defined(__cplusplus) # define ATTR_UNUSED(x) #elif defined(HAVE_ATTR_UNUSED) # define ATTR_UNUSED(x) x __attribute__((unused)) #else /* !HAVE_ATTR_UNUSED */ # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ ]) AC_MSG_RESULT($ac_cv_c_unused_attribute) if test $ac_cv_c_unused_attribute = yes; then AC_DEFINE(HAVE_ATTR_UNUSED, 1, [Whether the C compiler accepts the "unused" attribute]) fi ])dnl dnl Pre-fun for ACX_LIBTOOL_C_ONLY AC_DEFUN([ACX_LIBTOOL_C_PRE], [ # skip these tests, we do not need them. AC_DEFUN([AC_PROG_F77], [:]) AC_DEFUN([AC_PROG_FC], [:]) AC_DEFUN([AC_PROG_CXX], [:]) AC_DEFUN([AC_PROG_CXXCPP], [:]) AC_DEFUN([AC_PROG_OBJC], [:]) AC_DEFUN([AC_PROG_OBJCCPP], [:]) AC_DEFUN([AC_LIBTOOL_CXX], [:]) AC_DEFUN([AC_LIBTOOL_F77], [:]) # always use ./libtool unless override from commandline (libtool=mylibtool) if test -z "$libtool"; then libtool="./libtool" fi AC_SUBST(libtool) # avoid libtool max commandline length test on systems that fork slowly. AC_CANONICAL_HOST if echo "$host_os" | grep "sunos4" >/dev/null; then lt_cv_sys_max_cmd_len=32750; fi AC_PATH_TOOL(AR, ar, [false]) if test $AR = false; then AC_MSG_ERROR([Cannot find 'ar', please extend PATH to include it]) fi ]) dnl Perform libtool check, portably, only for C AC_DEFUN([ACX_LIBTOOL_C_ONLY], [ dnl as a requirement so that is gets called before LIBTOOL dnl because libtools 'AC_REQUIRE' names are right after this one, before dnl this function contents. AC_REQUIRE([ACX_LIBTOOL_C_PRE]) AC_PROG_LIBTOOL ]) dnl Detect if u_char type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_U_CHAR], [AC_CHECK_TYPE([u_char], , [AC_DEFINE([u_char], [unsigned char], [Define to 'unsigned char if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_WINSOCK2_H # include #endif ]) ]) dnl Detect if rlim_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_RLIM_T], [AC_CHECK_TYPE(rlim_t, , [AC_DEFINE([rlim_t], [unsigned long], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_RESOURCE_H # include #endif ]) ]) dnl Detect if socklen_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_SOCKLEN_T], [ AC_CHECK_TYPE(socklen_t, , [AC_DEFINE([socklen_t], [int], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_WS2TCPIP_H # include #endif ]) ]) dnl Detect if in_addr_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_IN_ADDR_T], [ AC_CHECK_TYPE(in_addr_t, [], [AC_DEFINE([in_addr_t], [uint32_t], [in_addr_t])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif ]) ]) dnl Detect if in_port_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_IN_PORT_T], [ AC_CHECK_TYPE(in_port_t, [], [AC_DEFINE([in_port_t], [uint16_t], [in_port_t])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif ]) ]) dnl Add option to disable the evil rpath. Check whether to use rpath or not. dnl Adds the --disable-rpath option. Uses trick to edit the ./libtool. AC_DEFUN([ACX_ARG_RPATH], [ AC_ARG_ENABLE(rpath, [ --disable-rpath disable hardcoded rpath (default=enabled)], enable_rpath=$enableval, enable_rpath=yes) if test "x$enable_rpath" = xno; then dnl AC_MSG_RESULT([Fixing libtool for -rpath problems.]) AC_CONFIG_COMMANDS([disable-rpath], [ sed < libtool > libtool-2 \ 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_RPATH_SED__ "/' mv libtool-2 libtool chmod 755 libtool libtool="./libtool" ]) fi ]) dnl Add a -R to the RUNTIME_PATH. Only if rpath is enabled and it is dnl an absolute path. dnl $1: the pathname to add. AC_DEFUN([ACX_RUNTIME_PATH_ADD], [ if test "x$enable_rpath" = xyes; then if echo "$1" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$1" fi fi ]) dnl Common code for both ACX_WITH_SSL and ACX_WITH_SSL_OPTIONAL dnl Takes one argument; the withval checked in those 2 functions dnl sets up the environment for the given openssl path AC_DEFUN([ACX_SSL_CHECKS], [ withval=$1 if test x_$withval != x_no; then AC_MSG_CHECKING(for SSL) if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes" AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.]) dnl assume /usr/include is already in the include-path. if test "$ssldir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$ssldir/include" LIBSSL_CPPFLAGS="$LIBSSL_CPPFLAGS -I$ssldir/include" fi break; fi done if test x_$found_ssl != x_yes; then AC_MSG_ERROR(Cannot find the SSL libraries in $withval) else AC_MSG_RESULT(found in $ssldir) HAVE_SSL=yes dnl assume /usr is already in the lib and dynlib paths. if test "$ssldir" != "/usr" -a "$ssldir" != ""; then LDFLAGS="$LDFLAGS -L$ssldir/lib" LIBSSL_LDFLAGS="$LIBSSL_LDFLAGS -L$ssldir/lib" ACX_RUNTIME_PATH_ADD([$ssldir/lib]) fi AC_MSG_CHECKING([for HMAC_Update in -lcrypto]) LIBS="$LIBS -lcrypto" LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto" AC_TRY_LINK(, [ int HMAC_Update(void); (void)HMAC_Update(); ], [ AC_MSG_RESULT(yes) AC_DEFINE([HAVE_HMAC_UPDATE], 1, [If you have HMAC_Update]) ], [ AC_MSG_RESULT(no) # check if -lwsock32 or -lgdi32 are needed. BAKLIBS="$LIBS" BAKSSLLIBS="$LIBSSL_LIBS" LIBS="$LIBS -lgdi32" LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32" AC_MSG_CHECKING([if -lcrypto needs -lgdi32]) AC_TRY_LINK([], [ int HMAC_Update(void); (void)HMAC_Update(); ],[ AC_DEFINE([HAVE_HMAC_UPDATE], 1, [If you have HMAC_Update]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -ldl" LIBSSL_LIBS="$LIBSSL_LIBS -ldl" AC_MSG_CHECKING([if -lcrypto needs -ldl]) AC_TRY_LINK([], [ int HMAC_Update(void); (void)HMAC_Update(); ],[ AC_DEFINE([HAVE_HMAC_UPDATE], 1, [If you have HMAC_Update]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" LIBS="$LIBS -ldl -pthread" LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread" AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread]) AC_TRY_LINK([], [ int HMAC_Update(void); (void)HMAC_Update(); ],[ AC_DEFINE([HAVE_HMAC_UPDATE], 1, [If you have HMAC_Update]) AC_MSG_RESULT(yes) ],[ AC_MSG_RESULT(no) AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) ]) ]) ]) ]) fi AC_SUBST(HAVE_SSL) AC_SUBST(RUNTIME_PATH) fi AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT]) ])dnl End of ACX_SSL_CHECKS dnl Check for SSL, where SSL is mandatory dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. dnl Checks main header files of SSL. dnl AC_DEFUN([ACX_WITH_SSL], [ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname], [enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[ ],[ withval="yes" ]) if test x_$withval = x_no; then AC_MSG_ERROR([Need SSL library to do digital signature cryptography]) fi ACX_SSL_CHECKS($withval) ])dnl End of ACX_WITH_SSL dnl Check for SSL, where ssl is optional (--without-ssl is allowed) dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. dnl Checks main header files of SSL. dnl AC_DEFUN([ACX_WITH_SSL_OPTIONAL], [ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname], [enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr)]),[ ],[ withval="yes" ]) ACX_SSL_CHECKS($withval) ])dnl End of ACX_WITH_SSL_OPTIONAL dnl Setup to use -lssl dnl To use -lcrypto, use the ACX_WITH_SSL setup (before this one). AC_DEFUN([ACX_LIB_SSL], [ # check if libssl needs libdl BAKLIBS="$LIBS" LIBS="-lssl $LIBS" AC_MSG_CHECKING([if libssl needs libdl]) AC_TRY_LINK_FUNC([SSL_CTX_new], [ AC_MSG_RESULT([no]) LIBS="$BAKLIBS" ] , [ AC_MSG_RESULT([yes]) LIBS="$BAKLIBS" AC_SEARCH_LIBS([dlopen], [dl]) ]) ])dnl End of ACX_LIB_SSL dnl Setup to use very large files (>2Gb). dnl setups fseeko and its own AC_DEFUN([ACX_SYS_LARGEFILE], [ AC_SYS_LARGEFILE dnl try to see if an additional _LARGEFILE_SOURCE 1 is needed to get fseeko ACX_CHECK_COMPILER_FLAG_NEEDED(-D_LARGEFILE_SOURCE=1, [ #include int test() { int a = fseeko(stdin, 0, 0); return a; } ], [CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE=1"]) ]) dnl Check getaddrinfo. dnl Works on linux, solaris, bsd and windows(links winsock). dnl defines HAVE_GETADDRINFO, USE_WINSOCK. AC_DEFUN([ACX_CHECK_GETADDRINFO_WITH_INCLUDES], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for getaddrinfo) ac_cv_func_getaddrinfo=no AC_LINK_IFELSE( [AC_LANG_SOURCE([[ #ifdef __cplusplus extern "C" { #endif char* getaddrinfo(); char* (*f) () = getaddrinfo; #ifdef __cplusplus } #endif int main() { ; return 0; } ]])], dnl this case on linux, solaris, bsd [ac_cv_func_getaddrinfo="yes" dnl see if on windows if test "$ac_cv_header_windows_h" = "yes"; then AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" LIBS="$LIBS -lws2_32" fi ], dnl no quick getaddrinfo, try mingw32 and winsock2 library. ORIGLIBS="$LIBS" LIBS="$LIBS -lws2_32" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #ifdef HAVE_WS2TCPIP_H #include #endif ], [ (void)getaddrinfo(NULL, NULL, NULL, NULL); ] )], [ ac_cv_func_getaddrinfo="yes" dnl already: LIBS="$LIBS -lws2_32" AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" ], [ ac_cv_func_getaddrinfo="no" LIBS="$ORIGLIBS" ]) ) AC_MSG_RESULT($ac_cv_func_getaddrinfo) if test $ac_cv_func_getaddrinfo = yes; then AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether getaddrinfo is available]) fi ])dnl Endof AC_CHECK_GETADDRINFO_WITH_INCLUDES dnl check if a function is deprecated. defines DEPRECATED_func in config.h. dnl $1: function name dnl $2: C-statement that calls the function. dnl $3: includes for the program. dnl $4: executes if yes dnl $5: executes if no AC_DEFUN([ACX_FUNC_DEPRECATED], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(if $1 is deprecated) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_cc_deprecated_$cache, [ echo '$3' >conftest.c echo 'void f(){ $2 }' >>conftest.c if test -z "`$CC -c conftest.c 2>&1 | grep deprecated`"; then eval "cv_cc_deprecated_$cache=no" else eval "cv_cc_deprecated_$cache=yes" fi rm -f conftest conftest.o conftest.c ]) if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then AC_MSG_RESULT(yes) AC_DEFINE_UNQUOTED(AS_TR_CPP([DEPRECATED_$1]), 1, [Whether $1 is deprecated]) : $4 else AC_MSG_RESULT(no) : $5 fi ])dnl end of ACX_FUNC_DEPRECATED dnl check if select and nonblocking sockets actually work. dnl Needs fork(2) and select(2). dnl defines NONBLOCKING_IS_BROKEN, and if that is true multiple reads from dnl a nonblocking socket do not work, a new call to select is necessary. AC_DEFUN([ACX_CHECK_NONBLOCKING_BROKEN], [ AC_MSG_CHECKING([if nonblocking sockets work]) if echo $target | grep mingw32 >/dev/null; then AC_MSG_RESULT([no (windows)]) AC_DEFINE([NONBLOCKING_IS_BROKEN], 1, [Define if the network stack does not fully support nonblocking io (causes lower performance).]) else AC_RUN_IFELSE([ AC_LANG_SOURCE([[ #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif int main(void) { int port; int sfd, cfd; int num = 10; int i, p; struct sockaddr_in a; /* test if select and nonblocking reads work well together */ /* open port. fork child to send 10 messages. select to read. then try to nonblocking read the 10 messages then, nonblocking read must give EAGAIN */ port = 12345 + (time(0)%32); sfd = socket(PF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket"); return 1; } memset(&a, 0, sizeof(a)); a.sin_family = AF_INET; a.sin_port = htons(port); a.sin_addr.s_addr = inet_addr("127.0.0.1"); if(bind(sfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("bind"); return 1; } if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) { perror("fcntl"); return 1; } cfd = socket(PF_INET, SOCK_DGRAM, 0); if(cfd == -1) { perror("client socket"); return 1; } a.sin_port = 0; if(bind(cfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("client bind"); return 1; } a.sin_port = htons(port); /* no handler, causes exit in 10 seconds */ alarm(10); /* send and receive on the socket */ if((p=fork()) == 0) { for(i=0; i #include #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif ], [ (void)mkdir("directory"); ], AC_MSG_RESULT(yes) AC_DEFINE(MKDIR_HAS_ONE_ARG, 1, [Define if mkdir has one argument.]) , AC_MSG_RESULT(no) ) ])dnl end of ACX_MKDIR_ONE_ARG dnl Check for ioctlsocket function. works on mingw32 too. AC_DEFUN([ACX_FUNC_IOCTLSOCKET], [ # check ioctlsocket AC_MSG_CHECKING(for ioctlsocket) AC_LINK_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_WINSOCK2_H #include #endif ], [ (void)ioctlsocket(0, 0, NULL); ])], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_IOCTLSOCKET, 1, [if the function 'ioctlsocket' is available]) ],[AC_MSG_RESULT(no)]) ])dnl end of ACX_FUNC_IOCTLSOCKET dnl detect malloc and provide malloc compat prototype. dnl $1: unique name for compat code AC_DEFUN([ACX_FUNC_MALLOC], [ AC_MSG_CHECKING([for GNU libc compatible malloc]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [[#if defined STDC_HEADERS || defined HAVE_STDLIB_H #include #else char *malloc (); #endif ]], [ if(malloc(0) != 0) return 1;]) ], [AC_MSG_RESULT([no]) AC_LIBOBJ(malloc) AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] , [AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])], [AC_MSG_RESULT([no (crosscompile)]) AC_LIBOBJ(malloc) AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] ) ]) dnl Define fallback for fseeko and ftello if needed. AC_DEFUN([AHX_CONFIG_FSEEKO], [ #ifndef HAVE_FSEEKO #define fseeko fseek #define ftello ftell #endif /* HAVE_FSEEKO */ ]) dnl Define RAND_MAX if not defined AC_DEFUN([AHX_CONFIG_RAND_MAX], [ #ifndef RAND_MAX #define RAND_MAX 2147483647 #endif ]) dnl Define MAXHOSTNAMELEN if not defined AC_DEFUN([AHX_CONFIG_MAXHOSTNAMELEN], [ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif ]) dnl Define IPV6_MIN_MTU if not defined AC_DEFUN([AHX_CONFIG_IPV6_MIN_MTU], [ #ifndef IPV6_MIN_MTU #define IPV6_MIN_MTU 1280 #endif /* IPV6_MIN_MTU */ ]) dnl provide snprintf, vsnprintf compat prototype dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_SNPRINTF], [ #ifndef HAVE_SNPRINTF #define snprintf snprintf_$1 #define vsnprintf vsnprintf_$1 #include int snprintf (char *str, size_t count, const char *fmt, ...); int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif /* HAVE_SNPRINTF */ ]) dnl provide inet_pton compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_PTON], [ #ifndef HAVE_INET_PTON #define inet_pton inet_pton_$1 int inet_pton(int af, const char* src, void* dst); #endif /* HAVE_INET_PTON */ ]) dnl provide inet_ntop compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_NTOP], [ #ifndef HAVE_INET_NTOP #define inet_ntop inet_ntop_$1 const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif ]) dnl provide inet_aton compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_INET_ATON], [ #ifndef HAVE_INET_ATON #define inet_aton inet_aton_$1 int inet_aton(const char *cp, struct in_addr *addr); #endif ]) dnl provide memmove compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_MEMMOVE], [ #ifndef HAVE_MEMMOVE #define memmove memmove_$1 void *memmove(void *dest, const void *src, size_t n); #endif ]) dnl provide strlcat compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_STRLCAT], [ #ifndef HAVE_STRLCAT #define strlcat strlcat_$1 size_t strlcat(char *dst, const char *src, size_t siz); #endif ]) dnl provide strlcpy compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_STRLCPY], [ #ifndef HAVE_STRLCPY #define strlcpy strlcpy_$1 size_t strlcpy(char *dst, const char *src, size_t siz); #endif ]) dnl provide gmtime_r compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_GMTIME_R], [ #ifndef HAVE_GMTIME_R #define gmtime_r gmtime_r_$1 struct tm *gmtime_r(const time_t *timep, struct tm *result); #endif ]) dnl provide reallocarray compat prototype. dnl $1: unique name for compat code AC_DEFUN([AHX_CONFIG_REALLOCARRAY], [ #ifndef HAVE_REALLOCARRAY #define reallocarray reallocarray$1 void* reallocarray(void *ptr, size_t nmemb, size_t size); #endif ]) dnl provide w32 compat definition for sleep AC_DEFUN([AHX_CONFIG_W32_SLEEP], [ #if !defined(HAVE_SLEEP) || defined(HAVE_WINDOWS_H) #define sleep(x) Sleep((x)*1000) /* on win32 */ #endif /* HAVE_SLEEP */ ]) dnl provide w32 compat definition for usleep AC_DEFUN([AHX_CONFIG_W32_USLEEP], [ #ifndef HAVE_USLEEP #define usleep(x) Sleep((x)/1000 + 1) /* on win32 */ #endif /* HAVE_USLEEP */ ]) dnl provide w32 compat definition for random AC_DEFUN([AHX_CONFIG_W32_RANDOM], [ #ifndef HAVE_RANDOM #define random rand /* on win32, for tests only (bad random) */ #endif /* HAVE_RANDOM */ ]) dnl provide w32 compat definition for srandom AC_DEFUN([AHX_CONFIG_W32_SRANDOM], [ #ifndef HAVE_SRANDOM #define srandom(x) srand(x) /* on win32, for tests only (bad random) */ #endif /* HAVE_SRANDOM */ ]) dnl provide w32 compat definition for FD_SET_T AC_DEFUN([AHX_CONFIG_W32_FD_SET_T], [ /* detect if we need to cast to unsigned int for FD_SET to avoid warnings */ #ifdef HAVE_WINSOCK2_H #define FD_SET_T (u_int) #else #define FD_SET_T #endif ]) dnl Remove an extension flag from CFLAGS, define replacement to be made. dnl Used by ACX_STRIP_EXT_FLAGS. dnl $1: the name of the flag, for example -D_GNU_SOURCE. AC_DEFUN([ACX_CFLAGS_STRIP], [ if echo $CFLAGS | grep " $1" >/dev/null 2>&1; then CFLAGS="`echo $CFLAGS | sed -e 's/ $1//g'`" AC_DEFINE(m4_bpatsubst(OMITTED_$1,[[-=]],_), 1, Put $1 define in config.h) fi ]) dnl Remove EXT flags from the CFLAGS and set them to be defined in config.h dnl use with ACX_DETERMINE_EXT_FLAGS. AC_DEFUN([ACX_STRIP_EXT_FLAGS], [ AC_MSG_NOTICE([Stripping extension flags...]) ACX_CFLAGS_STRIP(-D_GNU_SOURCE) ACX_CFLAGS_STRIP(-D_BSD_SOURCE) ACX_CFLAGS_STRIP(-D_DEFAULT_SOURCE) ACX_CFLAGS_STRIP(-D__EXTENSIONS__) ACX_CFLAGS_STRIP(-D_POSIX_C_SOURCE=200112) ACX_CFLAGS_STRIP(-D_XOPEN_SOURCE=600) ACX_CFLAGS_STRIP(-D_XOPEN_SOURCE_EXTENDED=1) ACX_CFLAGS_STRIP(-D_ALL_SOURCE) ACX_CFLAGS_STRIP(-D_LARGEFILE_SOURCE=1) ]) dnl End of ACX_STRIP_EXT_FLAGS dnl define one omitted flag for config.h dnl $1: flag name. -D_GNU_SOURCE dnl $2: replacement define. _GNU_SOURCE dnl $3: define value, 1 AC_DEFUN([AHX_CONFIG_FLAG_OMITTED], [#if defined($1) && !defined($2) #define $2 $3 [#]endif ]) dnl Wrapper for AHX_CONFIG_FLAG_OMITTED for -D style flags dnl $1: the -DNAME or -DNAME=value string. AC_DEFUN([AHX_CONFIG_FLAG_EXT], [AHX_CONFIG_FLAG_OMITTED(m4_bpatsubst(OMITTED_$1,[[-=]],_),m4_bpatsubst(m4_bpatsubst($1,-D,),=.*$,),m4_if(m4_bregexp($1,=),-1,1,m4_bpatsubst($1,^.*=,))) ]) dnl config.h part to define omitted cflags, use with ACX_STRIP_EXT_FLAGS. AC_DEFUN([AHX_CONFIG_EXT_FLAGS], [AHX_CONFIG_FLAG_EXT(-D_GNU_SOURCE) AHX_CONFIG_FLAG_EXT(-D_BSD_SOURCE) AHX_CONFIG_FLAG_EXT(-D_DEFAULT_SOURCE) AHX_CONFIG_FLAG_EXT(-D__EXTENSIONS__) AHX_CONFIG_FLAG_EXT(-D_POSIX_C_SOURCE=200112) AHX_CONFIG_FLAG_EXT(-D_XOPEN_SOURCE=600) AHX_CONFIG_FLAG_EXT(-D_XOPEN_SOURCE_EXTENDED=1) AHX_CONFIG_FLAG_EXT(-D_ALL_SOURCE) AHX_CONFIG_FLAG_EXT(-D_LARGEFILE_SOURCE=1) ]) dnl check if memcmp is using signed characters and replace if so. AC_DEFUN([ACX_CHECK_MEMCMP_SIGNED], [AC_MSG_CHECKING([if memcmp compares unsigned]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include int main(void) { char a = 255, b = 0; if(memcmp(&a, &b, 1) < 0) return 1; return 0; } ]])], [AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) AC_DEFINE([MEMCMP_IS_BROKEN], [1], [Define if memcmp() does not compare unsigned bytes]) AC_LIBOBJ([memcmp]) ], [ AC_MSG_RESULT([cross-compile no]) AC_DEFINE([MEMCMP_IS_BROKEN], [1], [Define if memcmp() does not compare unsigned bytes]) AC_LIBOBJ([memcmp]) ]) ]) dnl define memcmp to its replacement, pass unique id for program as arg AC_DEFUN([AHX_MEMCMP_BROKEN], [ #ifdef MEMCMP_IS_BROKEN #include "compat/memcmp.h" #define memcmp memcmp_$1 int memcmp(const void *x, const void *y, size_t n); #endif ]) dnl ACX_CHECK_SS_FAMILY - check for sockaddr_storage.ss_family AC_DEFUN([ACX_CHECK_SS_FAMILY], [AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], [], [ AC_CHECK_MEMBER([struct sockaddr_storage.__ss_family], [ AC_DEFINE([ss_family], [__ss_family], [Fallback member name for socket family in struct sockaddr_storage]) ],, [AC_INCLUDES_DEFAULT #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif ]) ], [AC_INCLUDES_DEFAULT #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif ]) ]) dnl Check if CC and linker support -fPIE and -pie. dnl If so, sets them in CFLAGS / LDFLAGS. AC_DEFUN([ACX_CHECK_PIE], [ AC_ARG_ENABLE([pie], AS_HELP_STRING([--enable-pie], [Enable Position-Independent Executable (eg. to fully benefit from ASLR, small performance penalty)])) AS_IF([test "x$enable_pie" = "xyes"], [ AC_MSG_CHECKING([if $CC supports PIE]) BAKLDFLAGS="$LDFLAGS" BAKCFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS -pie" CFLAGS="$CFLAGS -fPIE" AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then LDFLAGS="$BAKLDFLAGS" AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi rm -f conftest conftest.c conftest.o ], [LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) ]) ]) dnl Check if linker supports -Wl,-z,relro,-z,now. dnl If so, adds it to LDFLAGS. AC_DEFUN([ACX_CHECK_RELRO_NOW], [ AC_ARG_ENABLE([relro_now], AS_HELP_STRING([--enable-relro-now], [Enable full relocation binding at load-time (RELRO NOW, to protect GOT and .dtor areas)])) AS_IF([test "x$enable_relro_now" = "xyes"], [ AC_MSG_CHECKING([if $CC supports -Wl,-z,relro,-z,now]) BAKLDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then LDFLAGS="$BAKLDFLAGS" AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi rm -f conftest conftest.c conftest.o ], [LDFLAGS="$BAKLDFLAGS" ; AC_MSG_RESULT(no)]) ]) ]) dnl End of file nsd-4.1.26/remote.c0000664000175000017500000020422313376765335013512 0ustar wouterwouter/* * remote.c - remote control for the NSD daemon. * * Copyright (c) 2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains the remote control functionality for the daemon. * The remote control can be performed using either the commandline * nsd-control tool, or a TLS capable web browser. * The channel is secured using TLSv1, and certificates. * Both the server and the client(control tool) have their own keys. */ #include "config.h" #ifdef HAVE_SSL #ifdef HAVE_OPENSSL_SSL_H #include "openssl/ssl.h" #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #include #include #include #include #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "remote.h" #include "util.h" #include "xfrd.h" #include "xfrd-notify.h" #include "xfrd-tcp.h" #include "nsd.h" #include "options.h" #include "difffile.h" #include "ipc.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_NETDB_H # include #endif #ifdef HAVE_SYS_UN_H # include #endif /** number of seconds timeout on incoming remote control handshake */ #define REMOTE_CONTROL_TCP_TIMEOUT 120 /** repattern to master or slave */ #define REPAT_SLAVE 1 #define REPAT_MASTER 2 /** if you want zero to be inhibited in stats output. * it omits zeroes for types that have no acronym and unused-rcodes */ const int inhibit_zero = 1; /** * a busy control command connection, SSL state * Defined here to keep the definition private, and keep SSL out of the .h */ struct rc_state { /** the next item in list */ struct rc_state* next, *prev; /* if the event was added to the event_base */ int event_added; /** the commpoint */ struct event c; /** timeout for this state */ struct timeval tval; /** in the handshake part */ enum { rc_none, rc_hs_read, rc_hs_write } shake_state; /** the ssl state */ SSL* ssl; /** file descriptor */ int fd; /** the rc this is part of */ struct daemon_remote* rc; /** stats list next item */ struct rc_state* stats_next; /** stats list indicator (0 is not part of stats list, 1 is stats, * 2 is stats_noreset. */ int in_stats_list; }; /** * list of events for accepting connections */ struct acceptlist { struct acceptlist* next; int event_added; struct event c; char* ident; struct daemon_remote* rc; }; /** * The remote control state. */ struct daemon_remote { /** the master process for this remote control */ struct xfrd_state* xfrd; /** commpoints for accepting remote control connections */ struct acceptlist* accept_list; /* if certificates are used */ int use_cert; /** number of active commpoints that are handling remote control */ int active; /** max active commpoints */ int max_active; /** current commpoints busy; double linked, malloced */ struct rc_state* busy_list; /** commpoints waiting for stats to complete (also in busy_list) */ struct rc_state* stats_list; /** last time stats was reported */ struct timeval stats_time, boot_time; /** the SSL context for creating new SSL streams */ SSL_CTX* ctx; }; /** * Connection to print to, either SSL or plain over fd */ struct remote_stream { /** SSL structure, nonNULL if using SSL */ SSL* ssl; /** file descriptor for plain transfer */ int fd; }; typedef struct remote_stream RES; /** * Print fixed line of text over ssl connection in blocking mode * @param res: print to * @param text: the text. * @return false on connection failure. */ static int ssl_print_text(RES* res, const char* text); /** * printf style printing to the ssl connection * @param res: the RES connection to print to. Blocking. * @param format: printf style format string. * @return success or false on a network failure. */ static int ssl_printf(RES* res, const char* format, ...) ATTR_FORMAT(printf, 2, 3); /** * Read until \n is encountered * If stream signals EOF, the string up to then is returned (without \n). * @param res: the RES connection to read from. blocking. * @param buf: buffer to read to. * @param max: size of buffer. * @return false on connection failure. */ static int ssl_read_line(RES* res, char* buf, size_t max); /** perform the accept of a new remote control connection */ static void remote_accept_callback(int fd, short event, void* arg); /** perform remote control */ static void remote_control_callback(int fd, short event, void* arg); /** ---- end of private defines ---- **/ /** log ssl crypto err */ static void log_crypto_err(const char* str) { /* error:[error code]:[library name]:[function name]:[reason string] */ char buf[128]; unsigned long e; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); log_msg(LOG_ERR, "%s crypto %s", str, buf); while( (e=ERR_get_error()) ) { ERR_error_string_n(e, buf, sizeof(buf)); log_msg(LOG_ERR, "and additionally crypto %s", buf); } } #ifdef BIND8_STATS /** subtract timers and the values do not overflow or become negative */ static void timeval_subtract(struct timeval* d, const struct timeval* end, const struct timeval* start) { #ifndef S_SPLINT_S time_t end_usec = end->tv_usec; d->tv_sec = end->tv_sec - start->tv_sec; if(end_usec < start->tv_usec) { end_usec += 1000000; d->tv_sec--; } d->tv_usec = end_usec - start->tv_usec; #endif } #endif /* BIND8_STATS */ static int remote_setup_ctx(struct daemon_remote* rc, struct nsd_options* cfg) { char* s_cert; char* s_key; rc->ctx = SSL_CTX_new(SSLv23_server_method()); if(!rc->ctx) { log_crypto_err("could not SSL_CTX_new"); return 0; } /* no SSLv2, SSLv3 because has defects */ if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2){ log_crypto_err("could not set SSL_OP_NO_SSLv2"); return 0; } if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3){ log_crypto_err("could not set SSL_OP_NO_SSLv3"); return 0; } s_cert = cfg->server_cert_file; s_key = cfg->server_key_file; VERBOSITY(2, (LOG_INFO, "setup SSL certificates")); if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) { log_msg(LOG_ERR, "Error for server-cert-file: %s", s_cert); log_crypto_err("Error in SSL_CTX use_certificate_file"); return 0; } if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { log_msg(LOG_ERR, "Error for server-key-file: %s", s_key); log_crypto_err("Error in SSL_CTX use_PrivateKey_file"); return 0; } if(!SSL_CTX_check_private_key(rc->ctx)) { log_msg(LOG_ERR, "Error for server-key-file: %s", s_key); log_crypto_err("Error in SSL_CTX check_private_key"); return 0; } if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { log_crypto_err("Error setting up SSL_CTX verify locations"); return 0; } SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert)); SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL); return 1; } struct daemon_remote* daemon_remote_create(struct nsd_options* cfg) { struct daemon_remote* rc = (struct daemon_remote*)xalloc_zero( sizeof(*rc)); rc->max_active = 10; assert(cfg->control_enable); /* init SSL library */ #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); #endif ERR_load_SSL_strings(); #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else OPENSSL_init_ssl(0, NULL); #endif if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); size_t i; v = seed; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); log_msg(LOG_WARNING, "warning: no entropy, seeding openssl PRNG with time"); } if(options_remote_is_address(cfg)) { if(!remote_setup_ctx(rc, cfg)) { daemon_remote_delete(rc); return NULL; } rc->use_cert = 1; } else { struct ip_address_option* o; rc->ctx = NULL; rc->use_cert = 0; for(o = cfg->control_interface; o; o = o->next) { if(o->address && o->address[0] != '/') log_msg(LOG_WARNING, "control-interface %s is not using TLS, but plain transfer, because first control-interface in config file is a local socket (starts with a /).", o->address); } } /* and try to open the ports */ if(!daemon_remote_open_ports(rc, cfg)) { log_msg(LOG_ERR, "could not open remote control port"); daemon_remote_delete(rc); return NULL; } if(gettimeofday(&rc->boot_time, NULL) == -1) log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); rc->stats_time = rc->boot_time; return rc; } void daemon_remote_close(struct daemon_remote* rc) { struct rc_state* p, *np; struct acceptlist* h, *nh; if(!rc) return; /* close listen sockets */ h = rc->accept_list; while(h) { nh = h->next; if(h->event_added) event_del(&h->c); close(h->c.ev_fd); free(h->ident); free(h); h = nh; } rc->accept_list = NULL; /* close busy connection sockets */ p = rc->busy_list; while(p) { np = p->next; if(p->event_added) event_del(&p->c); if(p->ssl) SSL_free(p->ssl); close(p->c.ev_fd); free(p); p = np; } rc->busy_list = NULL; rc->active = 0; } void daemon_remote_delete(struct daemon_remote* rc) { if(!rc) return; daemon_remote_close(rc); if(rc->ctx) { SSL_CTX_free(rc->ctx); } free(rc); } static int create_tcp_accept_sock(struct addrinfo* addr, int* noproto) { #if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU))) int on = 1; #endif int s; *noproto = 0; if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) { *noproto = 1; log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); return -1; } #endif /* INET6 */ log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); return -1; } #ifdef SO_REUSEADDR if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); } #endif /* SO_REUSEADDR */ #if defined(INET6) && defined(IPV6_V6ONLY) if (addr->ai_family == AF_INET6 && setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); return -1; } #endif /* set it nonblocking */ /* (StevensUNP p463), if tcp listening socket is blocking, then it may block in accept, even if select() says readable. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno)); } /* Bind it... */ if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); return -1; } /* Listen to it... */ if (listen(s, TCP_BACKLOG_REMOTE) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); return -1; } return s; } /** * Add and open a new control port * @param rc: rc with result list. * @param ip: ip str * @param nr: port nr * @param noproto_is_err: if lack of protocol support is an error. * @return false on failure. */ static int add_open(struct daemon_remote* rc, struct nsd_options* cfg, const char* ip, int nr, int noproto_is_err) { struct addrinfo hints; struct addrinfo* res; struct acceptlist* hl; int noproto = 0; int fd, r; char port[15]; snprintf(port, sizeof(port), "%d", nr); port[sizeof(port)-1]=0; memset(&hints, 0, sizeof(hints)); assert(ip); if(ip[0] == '/') { /* This looks like a local socket */ fd = create_local_accept_sock(ip, &noproto); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same * group as the user we run as. */ if(fd != -1) { #ifdef HAVE_CHOWN if (cfg->username && cfg->username[0] && nsd.uid != (uid_t)-1) { if(chown(ip, nsd.uid, nsd.gid) == -1) VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s", (unsigned)nsd.uid, (unsigned)nsd.gid, ip, strerror(errno))); } chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); #else (void)cfg; #endif } } else { hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { log_msg(LOG_ERR, "control interface %s:%s getaddrinfo: %s %s", ip?ip:"default", port, gai_strerror(r), #ifdef EAI_SYSTEM r==EAI_SYSTEM?(char*)strerror(errno):"" #else "" #endif ); return 0; } /* open fd */ fd = create_tcp_accept_sock(res, &noproto); freeaddrinfo(res); } if(fd == -1 && noproto) { if(!noproto_is_err) return 1; /* return success, but do nothing */ log_msg(LOG_ERR, "cannot open control interface %s %d : " "protocol not supported", ip, nr); return 0; } if(fd == -1) { log_msg(LOG_ERR, "cannot open control interface %s %d", ip, nr); return 0; } /* alloc */ hl = (struct acceptlist*)xalloc_zero(sizeof(*hl)); hl->rc = rc; hl->ident = strdup(ip); if(!hl->ident) { log_msg(LOG_ERR, "malloc failure"); close(fd); free(hl); return 0; } hl->next = rc->accept_list; rc->accept_list = hl; hl->c.ev_fd = fd; hl->event_added = 0; return 1; } int daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg) { assert(cfg->control_enable && cfg->control_port); if(cfg->control_interface) { ip_address_option_type* p; for(p = cfg->control_interface; p; p = p->next) { if(!add_open(rc, cfg, p->address, cfg->control_port, 1)) { return 0; } } } else { /* defaults */ if(cfg->do_ip6 && !add_open(rc, cfg, "::1", cfg->control_port, 0)) { return 0; } if(cfg->do_ip4 && !add_open(rc, cfg, "127.0.0.1", cfg->control_port, 1)) { return 0; } } return 1; } void daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd) { int fd; struct acceptlist* p; if(!rc) return; rc->xfrd = xfrd; for(p = rc->accept_list; p; p = p->next) { /* add event */ fd = p->c.ev_fd; event_set(&p->c, fd, EV_PERSIST|EV_READ, remote_accept_callback, p); if(event_base_set(xfrd->event_base, &p->c) != 0) log_msg(LOG_ERR, "remote: cannot set event_base"); if(event_add(&p->c, NULL) != 0) log_msg(LOG_ERR, "remote: cannot add event"); p->event_added = 1; } } static void remote_accept_callback(int fd, short event, void* arg) { struct acceptlist *hl = (struct acceptlist*)arg; struct daemon_remote *rc = hl->rc; #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; int newfd; struct rc_state* n; if (!(event & EV_READ)) { return; } /* perform the accept */ addrlen = sizeof(addr); #ifndef HAVE_ACCEPT4 newfd = accept(fd, (struct sockaddr*)&addr, &addrlen); #else newfd = accept4(fd, (struct sockaddr*)&addr, &addrlen, SOCK_NONBLOCK); #endif if(newfd == -1) { if ( errno != EINTR && errno != EWOULDBLOCK #ifdef ECONNABORTED && errno != ECONNABORTED #endif /* ECONNABORTED */ #ifdef EPROTO && errno != EPROTO #endif /* EPROTO */ ) { log_msg(LOG_ERR, "accept failed: %s", strerror(errno)); } return; } /* create new commpoint unless we are servicing already */ if(rc->active >= rc->max_active) { log_msg(LOG_WARNING, "drop incoming remote control: " "too many connections"); close_exit: close(newfd); return; } #ifndef HAVE_ACCEPT4 if (fcntl(newfd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); goto close_exit; } #endif /* setup state to service the remote control command */ n = (struct rc_state*)calloc(1, sizeof(*n)); if(!n) { log_msg(LOG_ERR, "out of memory"); goto close_exit; } n->tval.tv_sec = REMOTE_CONTROL_TCP_TIMEOUT; n->tval.tv_usec = 0L; n->fd = newfd; event_set(&n->c, newfd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, n); if(event_base_set(xfrd->event_base, &n->c) != 0) { log_msg(LOG_ERR, "remote_accept: cannot set event_base"); free(n); goto close_exit; } if(event_add(&n->c, &n->tval) != 0) { log_msg(LOG_ERR, "remote_accept: cannot add event"); free(n); goto close_exit; } n->event_added = 1; if(2 <= verbosity) { if(hl->ident && hl->ident[0] == '/') { VERBOSITY(2, (LOG_INFO, "new control connection from %s", hl->ident)); } else { char s[128]; addr2str(&addr, s, sizeof(s)); VERBOSITY(2, (LOG_INFO, "new control connection from %s", s)); } } if(rc->ctx) { n->shake_state = rc_hs_read; n->ssl = SSL_new(rc->ctx); if(!n->ssl) { log_crypto_err("could not SSL_new"); event_del(&n->c); free(n); goto close_exit; } SSL_set_accept_state(n->ssl); (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(n->ssl, newfd)) { log_crypto_err("could not SSL_set_fd"); event_del(&n->c); SSL_free(n->ssl); free(n); goto close_exit; } } else { n->ssl = NULL; } n->rc = rc; n->stats_next = NULL; n->in_stats_list = 0; n->prev = NULL; n->next = rc->busy_list; if(n->next) n->next->prev = n; rc->busy_list = n; rc->active ++; /* perform the first nonblocking read already, for windows, * so it can return wouldblock. could be faster too. */ remote_control_callback(newfd, EV_READ, n); } /** delete from list */ static void state_list_remove_elem(struct rc_state** list, struct rc_state* todel) { if(todel->prev) todel->prev->next = todel->next; else *list = todel->next; if(todel->next) todel->next->prev = todel->prev; } /** delete from stats list */ static void stats_list_remove_elem(struct rc_state** list, struct rc_state* todel) { while(*list) { if( (*list) == todel) { *list = (*list)->stats_next; return; } list = &(*list)->stats_next; } } /** decrease active count and remove commpoint from busy list */ static void clean_point(struct daemon_remote* rc, struct rc_state* s) { if(s->in_stats_list) stats_list_remove_elem(&rc->stats_list, s); state_list_remove_elem(&rc->busy_list, s); rc->active --; if(s->event_added) event_del(&s->c); if(s->ssl) { SSL_shutdown(s->ssl); SSL_free(s->ssl); } close(s->c.ev_fd); free(s); } static int ssl_print_text(RES* res, const char* text) { int r; if(!res) return 0; if(res->ssl) { ERR_clear_error(); if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { VERBOSITY(2, (LOG_WARNING, "in SSL_write, peer " "closed connection")); return 0; } log_crypto_err("could not SSL_write"); return 0; } } else { if(write_socket(res->fd, text, strlen(text)) <= 0) { log_msg(LOG_ERR, "could not write: %s", strerror(errno)); return 0; } } return 1; } /** print text over the ssl connection */ static int ssl_print_vmsg(RES* ssl, const char* format, va_list args) { char msg[1024]; vsnprintf(msg, sizeof(msg), format, args); return ssl_print_text(ssl, msg); } /** printf style printing to the ssl connection */ static int ssl_printf(RES* ssl, const char* format, ...) { va_list args; int ret; va_start(args, format); ret = ssl_print_vmsg(ssl, format, args); va_end(args); return ret; } static int ssl_read_line(RES* res, char* buf, size_t max) { int r; size_t len = 0; if(!res) return 0; while(len < max) { if(res->ssl) { ERR_clear_error(); if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { buf[len] = 0; return 1; } log_crypto_err("could not SSL_read"); return 0; } } else { while(1) { ssize_t rr = read(res->fd, buf+len, 1); if(rr <= 0) { if(rr == 0) { buf[len] = 0; return 1; } if(errno == EINTR || errno == EAGAIN) continue; log_msg(LOG_ERR, "could not read: %s", strerror(errno)); return 0; } break; } } if(buf[len] == '\n') { /* return string without \n */ buf[len] = 0; return 1; } len++; } buf[max-1] = 0; log_msg(LOG_ERR, "control line too long (%d): %s", (int)max, buf); return 0; } /** skip whitespace, return new pointer into string */ static char* skipwhite(char* str) { /* EOS \0 is not a space */ while( isspace((unsigned char)*str) ) str++; return str; } /** send the OK to the control client */ static void send_ok(RES* ssl) { (void)ssl_printf(ssl, "ok\n"); } /** get zone argument (if any) or NULL, false on error */ static int get_zone_arg(RES* ssl, xfrd_state_type* xfrd, char* arg, struct zone_options** zo) { const dname_type* dname; if(!arg[0]) { /* no argument present, return NULL */ *zo = NULL; return 1; } dname = dname_parse(xfrd->region, arg); if(!dname) { ssl_printf(ssl, "error cannot parse zone name '%s'\n", arg); *zo = NULL; return 0; } *zo = zone_options_find(xfrd->nsd->options, dname); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); if(!*zo) { ssl_printf(ssl, "error zone %s not configured\n", arg); return 0; } return 1; } /** do the stop command */ static void do_stop(RES* ssl, xfrd_state_type* xfrd) { xfrd->need_to_send_shutdown = 1; if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } send_ok(ssl); } /** do the log_reopen command, it only needs reload_now */ static void do_log_reopen(RES* ssl, xfrd_state_type* xfrd) { xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the reload command */ static void do_reload(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the write command */ static void do_write(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zo?(const dname_type*)zo->node.key:NULL); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** do the notify command */ static void do_notify(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { struct notify_zone* n = (struct notify_zone*)rbtree_search( xfrd->notify_zones, (const dname_type*)zo->node.key); if(n) { xfrd_notify_start(n, xfrd); send_ok(ssl); } else { ssl_printf(ssl, "error zone does not have notify\n"); } } else { struct notify_zone* n; RBTREE_FOR(n, struct notify_zone*, xfrd->notify_zones) { xfrd_notify_start(n, xfrd); } send_ok(ssl); } } /** do the transfer command */ static void do_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; xfrd_zone_type* zone; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); if(zone) { xfrd_handle_notify_and_start_xfr(zone, NULL); send_ok(ssl); } else { ssl_printf(ssl, "error zone not slave\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { xfrd_handle_notify_and_start_xfr(zone, NULL); } ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); } } /** force transfer a zone */ static void force_transfer_zone(xfrd_zone_type* zone) { /* if in TCP transaction, stop it immediately. */ if(zone->tcp_conn != -1) xfrd_tcp_release(xfrd->tcp_set, zone); else if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); /* pretend we not longer have it and force any * zone to be downloaded (even same serial, w AXFR) */ zone->soa_disk_acquired = 0; zone->soa_nsd_acquired = 0; xfrd_handle_notify_and_start_xfr(zone, NULL); } /** do the force transfer command */ static void do_force_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; xfrd_zone_type* zone; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) { zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); if(zone) { force_transfer_zone(zone); send_ok(ssl); } else { ssl_printf(ssl, "error zone not slave\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { force_transfer_zone(zone); } ssl_printf(ssl, "ok, %lu zones\n", (unsigned long)xfrd->zones->count); } } static int print_soa_status(RES* ssl, const char* str, xfrd_soa_type* soa, time_t acq) { if(acq) { if(!ssl_printf(ssl, " %s: \"%u since %s\"\n", str, (unsigned)ntohl(soa->serial), xfrd_pretty_time(acq))) return 0; } else { if(!ssl_printf(ssl, " %s: none\n", str)) return 0; } return 1; } /** print zonestatus for one domain */ static int print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo) { xfrd_zone_type* xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, (const dname_type*)zo->node.key); struct notify_zone* nz = (struct notify_zone*)rbtree_search( xfrd->notify_zones, (const dname_type*)zo->node.key); if(!ssl_printf(ssl, "zone: %s\n", zo->name)) return 0; if(!zo->part_of_config) { if(!ssl_printf(ssl, " pattern: %s\n", zo->pattern->pname)) return 0; } if(nz) { if(nz->is_waiting) { if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n")) return 0; } else if(nz->notify_send_enable || nz->notify_send6_enable) { int i; if(!ssl_printf(ssl, " notify: \"send")) return 0; for(i=0; ipkts[i].dest) continue; if(!ssl_printf(ssl, " %s", nz->pkts[i].dest->ip_address_spec)) return 0; } if(!ssl_printf(ssl, " with serial %u\"\n", (unsigned)ntohl(nz->current_soa->serial))) return 0; } } if(!xz) { if(!ssl_printf(ssl, " state: master\n")) return 0; return 1; } if(!ssl_printf(ssl, " state: %s\n", (xz->state == xfrd_zone_ok)?"ok":( (xz->state == xfrd_zone_expired)?"expired":"refreshing"))) return 0; if(!print_soa_status(ssl, "served-serial", &xz->soa_nsd, xz->soa_nsd_acquired)) return 0; if(!print_soa_status(ssl, "commit-serial", &xz->soa_disk, xz->soa_disk_acquired)) return 0; if(xz->round_num != -1) { 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: \"%lu sec between attempts\"\n", (unsigned long)xz->timeout.tv_sec)) return 0; } /* UDP */ if(xz->udp_waiting) { if(!ssl_printf(ssl, " transfer: \"waiting-for-UDP-fd\"\n")) return 0; } else if(xz->zone_handler.ev_fd != -1 && xz->tcp_conn == -1) { if(!ssl_printf(ssl, " transfer: \"sent UDP to %s\"\n", xz->master->ip_address_spec)) return 0; } /* TCP */ if(xz->tcp_waiting) { if(!ssl_printf(ssl, " transfer: \"waiting-for-TCP-fd\"\n")) return 0; } else if(xz->tcp_conn != -1) { if(!ssl_printf(ssl, " transfer: \"TCP connected to %s\"\n", xz->master->ip_address_spec)) return 0; } return 1; } /** do the zonestatus command */ static void do_zonestatus(RES* ssl, xfrd_state_type* xfrd, char* arg) { struct zone_options* zo; if(!get_zone_arg(ssl, xfrd, arg, &zo)) return; if(zo) (void)print_zonestatus(ssl, xfrd, zo); else { RBTREE_FOR(zo, struct zone_options*, xfrd->nsd->options->zone_options) { if(!print_zonestatus(ssl, xfrd, zo)) return; } } } /** do the verbosity command */ static void do_verbosity(RES* ssl, char* str) { int val = atoi(str); if(strcmp(str, "") == 0) { ssl_printf(ssl, "verbosity %d\n", verbosity); return; } if(val == 0 && strcmp(str, "0") != 0) { ssl_printf(ssl, "error in verbosity number syntax: %s\n", str); return; } verbosity = val; task_new_set_verbosity(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, val); xfrd_set_reload_now(xfrd); send_ok(ssl); } /** find second argument, modifies string */ static int find_arg2(RES* ssl, char* arg, char** arg2) { char* as = strrchr(arg, ' '); if(as) { as[0]=0; *arg2 = as+1; while(isspace((unsigned char)*as) && as > arg) as--; as[0]=0; return 1; } ssl_printf(ssl, "error could not find next argument " "after %s\n", arg); return 0; } /** do the status command */ static void do_status(RES* ssl, xfrd_state_type* xfrd) { if(!ssl_printf(ssl, "version: %s\n", PACKAGE_VERSION)) return; if(!ssl_printf(ssl, "verbosity: %d\n", verbosity)) return; #ifdef RATELIMIT if(!ssl_printf(ssl, "ratelimit: %d\n", (int)xfrd->nsd->options->rrl_ratelimit)) return; #else (void)xfrd; #endif } /** do the stats command */ static void do_stats(struct daemon_remote* rc, int peek, struct rc_state* rs) { #ifdef BIND8_STATS /* queue up to get stats after a reload is done (to gather statistics * from the servers) */ assert(!rs->in_stats_list); if(peek) rs->in_stats_list = 2; else rs->in_stats_list = 1; rs->stats_next = rc->stats_list; rc->stats_list = rs; /* block the tcp waiting for the reload */ event_del(&rs->c); rs->event_added = 0; /* force a reload */ xfrd_set_reload_now(xfrd); #else (void)rc; (void)peek; (void)ssl_printf(rs->ssl, "error no stats enabled at compile time\n"); #endif /* BIND8_STATS */ } /** see if we have more zonestatistics entries and it has to be incremented */ static void zonestat_inc_ifneeded(xfrd_state_type* xfrd) { #ifdef USE_ZONE_STATS if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe) task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, xfrd->nsd->options->zonestatnames->count); #else (void)xfrd; #endif /* USE_ZONE_STATS */ } /** perform the changezone command for one zone */ static int perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; char* arg2 = NULL; if(!find_arg2(ssl, arg, &arg2)) return 0; /* if we add it to the xfrd now, then xfrd could download AXFR and * store it and the NSD-reload would see it in the difffile before * it sees the add-config task. */ /* thus: AXFRs and IXFRs must store the pattern name in the * difffile, so that it can be added when the AXFR or IXFR is seen. */ /* check that the pattern exists */ if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { (void)ssl_printf(ssl, "error pattern %s does not exist\n", arg2); return 0; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if zone is a duplicate */ if( (zopt=zone_options_find(xfrd->nsd->options, dname)) ) { if(zopt->part_of_config) { (void)ssl_printf(ssl, "error zone defined in nsd.conf, " "cannot delete it in this manner: remove it from " "nsd.conf yourself and repattern\n"); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; return 0; } /* found the zone, now delete it */ /* create deletion task */ /* this deletion task is processed before the addition task, * that is created below, in the same reload process, causing * a seamless change from one to the other, with no downtime * for the zone. */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); } else { (void)ssl_printf(ssl, "zone %s did not exist, creating", arg); } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; /* add to zonelist and adds to config in memory */ zopt = zone_list_add(xfrd->nsd->options, arg, arg2); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); return 0; } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, arg, arg2, getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } return 1; } /** perform the addzone command for one zone */ static int perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; char* arg2 = NULL; if(!find_arg2(ssl, arg, &arg2)) return 0; /* if we add it to the xfrd now, then xfrd could download AXFR and * store it and the NSD-reload would see it in the difffile before * it sees the add-config task. */ /* thus: AXFRs and IXFRs must store the pattern name in the * difffile, so that it can be added when the AXFR or IXFR is seen. */ /* check that the pattern exists */ if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { (void)ssl_printf(ssl, "error pattern %s does not exist\n", arg2); return 0; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if zone is a duplicate */ if( (zopt=zone_options_find(xfrd->nsd->options, dname)) ) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); (void)ssl_printf(ssl, "zone %s already exists\n", arg); return 1; } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; /* add to zonelist and adds to config in memory */ zopt = zone_list_add(xfrd->nsd->options, arg, arg2); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); return 0; } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, arg, arg2, getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } return 1; } /** perform the delzone command for one zone */ static int perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); return 0; } /* see if we have the zone in question */ zopt = zone_options_find(xfrd->nsd->options, dname); if(!zopt) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); /* nothing to do */ if(!ssl_printf(ssl, "warning zone %s not present\n", arg)) return 0; return 0; } /* see if it can be deleted */ if(zopt->part_of_config) { region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); (void)ssl_printf(ssl, "error zone defined in nsd.conf, " "cannot delete it in this manner: remove it from " "nsd.conf yourself and repattern\n"); return 0; } /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); return 1; } /** do the addzone command */ static void do_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_addzone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the delzone command */ static void do_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_delzone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the changezone command */ static void do_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) { if(!perform_changezone(ssl, xfrd, arg)) return; send_ok(ssl); } /** do the addzones command */ static void do_addzones(RES* ssl, xfrd_state_type* xfrd) { char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { if(buf[0] == 0x04 && buf[1] == 0) break; /* end of transmission */ if(!perform_addzone(ssl, xfrd, buf)) { if(!ssl_printf(ssl, "error for input line '%s'\n", buf)) return; } else { if(!ssl_printf(ssl, "added: %s\n", buf)) return; num++; } } (void)ssl_printf(ssl, "added %d zones\n", num); } /** do the delzones command */ static void do_delzones(RES* ssl, xfrd_state_type* xfrd) { char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { if(buf[0] == 0x04 && buf[1] == 0) break; /* end of transmission */ if(!perform_delzone(ssl, xfrd, buf)) { if(!ssl_printf(ssl, "error for input line '%s'\n", buf)) return; } else { if(!ssl_printf(ssl, "removed: %s\n", buf)) return; num++; } } (void)ssl_printf(ssl, "deleted %d zones\n", num); } /** remove TSIG key from config and add task so that reload does too */ static void remove_key(xfrd_state_type* xfrd, const char* kname) { /* add task before deletion because the name string could be deleted */ task_new_del_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, kname); key_options_remove(xfrd->nsd->options, kname); xfrd_set_reload_now(xfrd); /* this is executed when the current control command ends, thus the entire config changes are bunched up */ } /** add TSIG key to config and add task so that reload does too */ static void add_key(xfrd_state_type* xfrd, struct key_options* k) { key_options_add_modify(xfrd->nsd->options, k); task_new_add_key(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, k); xfrd_set_reload_now(xfrd); } /** check if keys have changed */ static void repat_keys(xfrd_state_type* xfrd, struct nsd_options* newopt) { struct nsd_options* oldopt = xfrd->nsd->options; struct key_options* k; /* find deleted keys */ k = (struct key_options*)rbtree_first(oldopt->keys); while((rbnode_type*)k != RBTREE_NULL) { struct key_options* next = (struct key_options*)rbtree_next( (rbnode_type*)k); if(!key_options_find(newopt, k->name)) remove_key(xfrd, k->name); k = next; } /* find added or changed keys */ RBTREE_FOR(k, struct key_options*, newopt->keys) { struct key_options* origk = key_options_find(oldopt, k->name); if(!origk) add_key(xfrd, k); else if(!key_options_equal(k, origk)) add_key(xfrd, k); } } /** find zone given the implicit pattern */ static const dname_type* parse_implicit_name(xfrd_state_type* xfrd,const char* pname) { if(strncmp(pname, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)) != 0) return NULL; return dname_parse(xfrd->region, pname + strlen(PATTERN_IMPLICIT_MARKER)); } /** remove cfgzone and add task so that reload does too */ static void remove_cfgzone(xfrd_state_type* xfrd, const char* pname) { /* dname and find the zone for the implicit pattern */ struct zone_options* zopt = NULL; const dname_type* dname = parse_implicit_name(xfrd, pname); if(!dname) { /* should have a parseable name, but it did not */ return; } /* find the zone entry for the implicit pattern */ zopt = zone_options_find(xfrd->nsd->options, dname); if(!zopt) { /* this should not happen; implicit pattern has zone entry */ region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); return; } /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); xfrd_set_reload_now(xfrd); /* delete it in xfrd */ if(zone_is_slave(zopt)) { xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); /* delete from zoneoptions */ zone_options_delete(xfrd->nsd->options, zopt); /* recycle parsed dname */ region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); } /** add cfgzone and add task so that reload does too */ static void add_cfgzone(xfrd_state_type* xfrd, const char* pname) { /* add to our zonelist */ struct zone_options* zopt = zone_options_create( xfrd->nsd->options->region); if(!zopt) return; zopt->part_of_config = 1; zopt->name = region_strdup(xfrd->nsd->options->region, pname + strlen(PATTERN_IMPLICIT_MARKER)); zopt->pattern = pattern_options_find(xfrd->nsd->options, pname); if(!zopt->name || !zopt->pattern) return; if(!nsd_options_insert_zone(xfrd->nsd->options, zopt)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", zopt->name, pname); } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, zopt->name, pname, getzonestatid(xfrd->nsd->options, zopt)); /* zonestat_inc is done after the entire config file has been done */ xfrd_set_reload_now(xfrd); /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } } /** remove pattern and add task so that reload does too */ static void remove_pat(xfrd_state_type* xfrd, const char* name) { /* add task before deletion, because name-string could be deleted */ task_new_del_pattern(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, name); pattern_options_remove(xfrd->nsd->options, name); xfrd_set_reload_now(xfrd); } /** add pattern and add task so that reload does too */ static void add_pat(xfrd_state_type* xfrd, struct pattern_options* p) { pattern_options_add_modify(xfrd->nsd->options, p); task_new_add_pattern(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, p); xfrd_set_reload_now(xfrd); } /** interrupt zones that are using changed or removed patterns */ static void repat_interrupt_zones(xfrd_state_type* xfrd, struct nsd_options* newopt) { /* if masterlist changed: * interrupt slave zone (UDP or TCP) transfers. * slave zones reset master to start of list. */ xfrd_zone_type* xz; struct notify_zone* nz; RBTREE_FOR(xz, xfrd_zone_type*, xfrd->zones) { struct pattern_options* oldp = xz->zone_options->pattern; struct pattern_options* newp = pattern_options_find(newopt, oldp->pname); if(!newp || !acl_list_equal(oldp->request_xfr, newp->request_xfr)) { /* interrupt transfer */ if(xz->tcp_conn != -1) { xfrd_tcp_release(xfrd->tcp_set, xz); xfrd_set_refresh_now(xz); } else if(xz->zone_handler.ev_fd != -1) { xfrd_udp_release(xz); xfrd_set_refresh_now(xz); } xz->master = 0; xz->master_num = 0; xz->next_master = -1; xz->round_num = -1; /* fresh set of retries */ } } /* if notify list changed: * interrupt notify that is busy. * reset notify to start of list. (clear all other reset_notify) */ RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) { struct pattern_options* oldp = nz->options->pattern; struct pattern_options* newp = pattern_options_find(newopt, oldp->pname); if(!newp || !acl_list_equal(oldp->notify, newp->notify)) { /* interrupt notify */ if(nz->notify_send_enable) { notify_disable(nz); /* set to restart the notify after the * pattern has been changed. */ nz->notify_restart = 2; } else { nz->notify_restart = 1; } } else { nz->notify_restart = 0; } } } /** for notify, after the pattern changes, restart the affected notifies */ static void repat_interrupt_notify_start(xfrd_state_type* xfrd) { struct notify_zone* nz; RBTREE_FOR(nz, struct notify_zone*, xfrd->notify_zones) { if(nz->notify_restart) { if(nz->notify_current) nz->notify_current = nz->options->pattern->notify; if(nz->notify_restart == 2) { if(nz->notify_restart) xfrd_notify_start(nz, xfrd); } } } } /** check if patterns have changed */ static void repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) { /* zones that use changed patterns must have: * - their AXFR/IXFR interrupted: try again, acl may have changed. * if the old master/key still exists, OK, fix master-numptrs and * keep going. Otherwise, stop xfer and reset TSIG. * - send NOTIFY reset to start of NOTIFY list (and TSIG reset). */ struct nsd_options* oldopt = xfrd->nsd->options; struct pattern_options* p; int search_zones = 0; repat_interrupt_zones(xfrd, newopt); /* find deleted patterns */ p = (struct pattern_options*)rbtree_first(oldopt->patterns); while((rbnode_type*)p != RBTREE_NULL) { struct pattern_options* next = (struct pattern_options*) rbtree_next((rbnode_type*)p); if(!pattern_options_find(newopt, p->pname)) { if(p->implicit) { /* first remove its zone */ VERBOSITY(1, (LOG_INFO, "zone removed from config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER))); remove_cfgzone(xfrd, p->pname); } remove_pat(xfrd, p->pname); } p = next; } /* find added or changed patterns */ RBTREE_FOR(p, struct pattern_options*, newopt->patterns) { struct pattern_options* origp = pattern_options_find(oldopt, p->pname); if(!origp) { /* no zones can use it, no zone_interrupt needed */ add_pat(xfrd, p); if(p->implicit) { VERBOSITY(1, (LOG_INFO, "zone added to config: %s", p->pname + strlen(PATTERN_IMPLICIT_MARKER))); add_cfgzone(xfrd, p->pname); } } else if(!pattern_options_equal(p, origp)) { uint8_t newstate = 0; if (p->request_xfr && !origp->request_xfr) { newstate = REPAT_SLAVE; } else if (!p->request_xfr && origp->request_xfr) { newstate = REPAT_MASTER; } add_pat(xfrd, p); if (p->implicit && newstate) { const dname_type* dname = parse_implicit_name(xfrd, p->pname); if (dname) { if (newstate == REPAT_SLAVE) { struct zone_options* zopt = zone_options_find( oldopt, dname); if (zopt) { xfrd_init_slave_zone( xfrd, zopt); } } else if (newstate == REPAT_MASTER) { xfrd_del_slave_zone(xfrd, dname); } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); } } else if(!p->implicit && newstate) { /* search all zones with this pattern */ search_zones = 1; origp->xfrd_flags = newstate; } } } if (search_zones) { struct zone_options* zone_opt; /* search in oldopt because 1) it contains zonelist zones, * and 2) you need oldopt(existing) to call xfrd_init */ RBTREE_FOR(zone_opt, struct zone_options*, oldopt->zone_options) { struct pattern_options* oldp = zone_opt->pattern; if (!oldp->implicit) { if (oldp->xfrd_flags == REPAT_SLAVE) { /* xfrd needs stable reference so get * it from the oldopt(modified) tree */ xfrd_init_slave_zone(xfrd, zone_opt); } else if (oldp->xfrd_flags == REPAT_MASTER) { xfrd_del_slave_zone(xfrd, (const dname_type*) zone_opt->node.key); } oldp->xfrd_flags = 0; } } } repat_interrupt_notify_start(xfrd); } /** true if options are different that can be set via repat. */ static int repat_options_changed(xfrd_state_type* xfrd, struct nsd_options* newopt) { #ifdef RATELIMIT if(xfrd->nsd->options->rrl_ratelimit != newopt->rrl_ratelimit) return 1; if(xfrd->nsd->options->rrl_whitelist_ratelimit != newopt->rrl_whitelist_ratelimit) return 1; if(xfrd->nsd->options->rrl_slip != newopt->rrl_slip) return 1; #else (void)xfrd; (void)newopt; #endif return 0; } /** check if global options have changed */ static void repat_options(xfrd_state_type* xfrd, struct nsd_options* newopt) { if(repat_options_changed(xfrd, newopt)) { /* update our options */ #ifdef RATELIMIT xfrd->nsd->options->rrl_ratelimit = newopt->rrl_ratelimit; xfrd->nsd->options->rrl_whitelist_ratelimit = newopt->rrl_whitelist_ratelimit; xfrd->nsd->options->rrl_slip = newopt->rrl_slip; #endif task_new_opt_change(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, newopt); xfrd_set_reload_now(xfrd); } } /** print errors over ssl, gets pointer-to-pointer to ssl, so it can set * the pointer to NULL on failure and stop printing */ static void print_ssl_cfg_err(void* arg, const char* str) { RES** ssl = (RES**)arg; if(!*ssl) return; if(!ssl_printf(*ssl, "%s", str)) *ssl = NULL; /* failed, stop printing */ } /** do the repattern command: reread config file and apply keys, patterns */ static void do_repattern(RES* ssl, xfrd_state_type* xfrd) { region_type* region = region_create(xalloc, free); struct nsd_options* opt; const char* cfgfile = xfrd->nsd->options->configfile; /* check chroot and configfile, if possible to reread */ if(xfrd->nsd->chrootdir) { size_t l = strlen(xfrd->nsd->chrootdir); while(l>0 && xfrd->nsd->chrootdir[l-1] == '/') --l; if(strncmp(xfrd->nsd->chrootdir, cfgfile, l) != 0) { ssl_printf(ssl, "error %s is not relative to %s: " "chroot prevents reread of config\n", cfgfile, xfrd->nsd->chrootdir); region_destroy(region); return; } cfgfile += l; } ssl_printf(ssl, "reconfig start, read %s\n", cfgfile); opt = nsd_options_create(region); if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl)) { /* error already printed */ region_destroy(region); return; } /* check for differences in TSIG keys and patterns, and apply, * first the keys, so that pattern->keyptr can be set right. */ repat_keys(xfrd, opt); repat_patterns(xfrd, opt); repat_options(xfrd, opt); zonestat_inc_ifneeded(xfrd); send_ok(ssl); region_destroy(region); } /** do the serverpid command: printout pid of server process */ static void do_serverpid(RES* ssl, xfrd_state_type* xfrd) { (void)ssl_printf(ssl, "%u\n", (unsigned)xfrd->reload_pid); } /** check for name with end-of-string, space or tab after it */ static int cmdcmp(char* p, const char* cmd, size_t len) { return strncmp(p,cmd,len)==0 && (p[len]==0||p[len]==' '||p[len]=='\t'); } /** execute a remote control command */ static void execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, struct rc_state* rs) { char* p = skipwhite(cmd); /* compare command */ if(cmdcmp(p, "stop", 4)) { do_stop(ssl, rc->xfrd); } else if(cmdcmp(p, "reload", 6)) { do_reload(ssl, rc->xfrd, skipwhite(p+6)); } else if(cmdcmp(p, "write", 5)) { do_write(ssl, rc->xfrd, skipwhite(p+5)); } else if(cmdcmp(p, "status", 6)) { do_status(ssl, rc->xfrd); } else if(cmdcmp(p, "stats_noreset", 13)) { do_stats(rc, 1, rs); } else if(cmdcmp(p, "stats", 5)) { do_stats(rc, 0, rs); } else if(cmdcmp(p, "log_reopen", 10)) { do_log_reopen(ssl, rc->xfrd); } else if(cmdcmp(p, "addzone", 7)) { do_addzone(ssl, rc->xfrd, skipwhite(p+7)); } else if(cmdcmp(p, "delzone", 7)) { do_delzone(ssl, rc->xfrd, skipwhite(p+7)); } else if(cmdcmp(p, "changezone", 10)) { do_changezone(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "addzones", 8)) { do_addzones(ssl, rc->xfrd); } else if(cmdcmp(p, "delzones", 8)) { do_delzones(ssl, rc->xfrd); } else if(cmdcmp(p, "notify", 6)) { do_notify(ssl, rc->xfrd, skipwhite(p+6)); } else if(cmdcmp(p, "transfer", 8)) { do_transfer(ssl, rc->xfrd, skipwhite(p+8)); } else if(cmdcmp(p, "force_transfer", 14)) { do_force_transfer(ssl, rc->xfrd, skipwhite(p+14)); } else if(cmdcmp(p, "zonestatus", 10)) { do_zonestatus(ssl, rc->xfrd, skipwhite(p+10)); } else if(cmdcmp(p, "verbosity", 9)) { do_verbosity(ssl, skipwhite(p+9)); } else if(cmdcmp(p, "repattern", 9)) { do_repattern(ssl, rc->xfrd); } else if(cmdcmp(p, "reconfig", 8)) { do_repattern(ssl, rc->xfrd); } else if(cmdcmp(p, "serverpid", 9)) { do_serverpid(ssl, rc->xfrd); } else { (void)ssl_printf(ssl, "error unknown command '%s'\n", p); } } /** handle remote control request */ static void handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) { int r; char pre[10]; char magic[8]; char buf[1024]; if (fcntl(s->c.ev_fd, F_SETFL, 0) == -1) { /* set blocking */ log_msg(LOG_ERR, "cannot fcntl rc: %s", strerror(errno)); } /* try to read magic UBCT[version]_space_ string */ if(res->ssl) { ERR_clear_error(); if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) { if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) return; log_crypto_err("could not SSL_read"); return; } } else { while(1) { ssize_t rr = read(res->fd, magic, sizeof(magic)-1); if(rr <= 0) { if(rr == 0) return; if(errno == EINTR || errno == EAGAIN) continue; log_msg(LOG_ERR, "could not read: %s", strerror(errno)); return; } r = (int)rr; break; } } magic[7] = 0; if( r != 7 || strncmp(magic, "NSDCT", 5) != 0) { VERBOSITY(2, (LOG_INFO, "control connection has bad header")); /* probably wrong tool connected, ignore it completely */ return; } /* read the command line */ if(!ssl_read_line(res, buf, sizeof(buf))) { return; } snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION); if(strcmp(magic, pre) != 0) { VERBOSITY(2, (LOG_INFO, "control connection had bad " "version %s, cmd: %s", magic, buf)); ssl_printf(res, "error version mismatch\n"); return; } VERBOSITY(2, (LOG_INFO, "control cmd: %s", buf)); /* figure out what to do */ execute_cmd(rc, res, buf, s); } /** handle SSL_do_handshake changes to the file descriptor to wait for later */ static void remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, int r, int r2) { if(r2 == SSL_ERROR_WANT_READ) { if(s->shake_state == rc_hs_read) { /* try again later */ return; } s->shake_state = rc_hs_read; event_del(&s->c); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, s); if(event_base_set(xfrd->event_base, &s->c) != 0) log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); return; } else if(r2 == SSL_ERROR_WANT_WRITE) { if(s->shake_state == rc_hs_write) { /* try again later */ return; } s->shake_state = rc_hs_write; event_del(&s->c); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE, remote_control_callback, s); if(event_base_set(xfrd->event_base, &s->c) != 0) log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); return; } else { if(r == 0) log_msg(LOG_ERR, "remote control connection closed prematurely"); log_crypto_err("remote control failed ssl"); clean_point(rc, s); } } static void remote_control_callback(int fd, short event, void* arg) { RES res; struct rc_state* s = (struct rc_state*)arg; struct daemon_remote* rc = s->rc; int r; if( (event&EV_TIMEOUT) ) { log_msg(LOG_ERR, "remote control timed out"); clean_point(rc, s); return; } if(s->ssl) { /* (continue to) setup the SSL connection */ ERR_clear_error(); r = SSL_do_handshake(s->ssl); if(r != 1) { int r2 = SSL_get_error(s->ssl, r); remote_handshake_later(rc, s, fd, r, r2); return; } s->shake_state = rc_none; } /* once handshake has completed, check authentication */ if (!rc->use_cert) { VERBOSITY(3, (LOG_INFO, "unauthenticated remote control connection")); } else if(SSL_get_verify_result(s->ssl) == X509_V_OK) { X509* x = SSL_get_peer_certificate(s->ssl); if(!x) { VERBOSITY(2, (LOG_INFO, "remote control connection " "provided no client certificate")); clean_point(rc, s); return; } VERBOSITY(3, (LOG_INFO, "remote control connection authenticated")); X509_free(x); } else { VERBOSITY(2, (LOG_INFO, "remote control connection failed to " "authenticate with client certificate")); clean_point(rc, s); return; } /* if OK start to actually handle the request */ res.ssl = s->ssl; res.fd = fd; handle_req(rc, s, &res); if(!s->in_stats_list) { VERBOSITY(3, (LOG_INFO, "remote control operation completed")); clean_point(rc, s); } } #ifdef BIND8_STATS static const char* opcode2str(int o) { switch(o) { case OPCODE_QUERY: return "QUERY"; case OPCODE_IQUERY: return "IQUERY"; case OPCODE_STATUS: return "STATUS"; case OPCODE_NOTIFY: return "NOTIFY"; case OPCODE_UPDATE: return "UPDATE"; default: return "OTHER"; } } /** print long number */ static int print_longnum(RES* ssl, char* desc, uint64_t x) { if(x > (uint64_t)1024*1024*1024) { /* more than a Gb */ size_t front = (size_t)(x / (uint64_t)1000000); size_t back = (size_t)(x % (uint64_t)1000000); return ssl_printf(ssl, "%s%lu%6.6lu\n", desc, (unsigned long)front, (unsigned long)back); } else { return ssl_printf(ssl, "%s%lu\n", desc, (unsigned long)x); } } /* print one block of statistics. n is name and d is delimiter */ static void print_stat_block(RES* ssl, char* n, char* d, struct nsdst* st) { const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", "BADVERS" }; size_t i; for(i=0; i<= 255; i++) { if(inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; if(!ssl_printf(ssl, "%s%snum.type.%s=%lu\n", n, d, rrtype_to_string(i), (unsigned long)st->qtype[i])) return; } /* opcode */ for(i=0; i<6; i++) { if(inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) continue; if(!ssl_printf(ssl, "%s%snum.opcode.%s=%lu\n", n, d, opcode2str(i), (unsigned long)st->opcode[i])) return; } /* qclass */ for(i=0; i<4; i++) { if(inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; if(!ssl_printf(ssl, "%s%snum.class.%s=%lu\n", n, d, rrclass_to_string(i), (unsigned long)st->qclass[i])) return; } /* rcode */ for(i=0; i<17; i++) { if(inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /* NSD does not use larger */ continue; if(!ssl_printf(ssl, "%s%snum.rcode.%s=%lu\n", n, d, rcstr[i], (unsigned long)st->rcode[i])) return; } /* edns */ if(!ssl_printf(ssl, "%s%snum.edns=%lu\n", n, d, (unsigned long)st->edns)) return; /* ednserr */ if(!ssl_printf(ssl, "%s%snum.ednserr=%lu\n", n, d, (unsigned long)st->ednserr)) return; /* qudp */ if(!ssl_printf(ssl, "%s%snum.udp=%lu\n", n, d, (unsigned long)st->qudp)) return; /* qudp6 */ if(!ssl_printf(ssl, "%s%snum.udp6=%lu\n", n, d, (unsigned long)st->qudp6)) return; /* ctcp */ if(!ssl_printf(ssl, "%s%snum.tcp=%lu\n", n, d, (unsigned long)st->ctcp)) return; /* ctcp6 */ if(!ssl_printf(ssl, "%s%snum.tcp6=%lu\n", n, d, (unsigned long)st->ctcp6)) return; /* nona */ if(!ssl_printf(ssl, "%s%snum.answer_wo_aa=%lu\n", n, d, (unsigned long)st->nona)) return; /* rxerr */ if(!ssl_printf(ssl, "%s%snum.rxerr=%lu\n", n, d, (unsigned long)st->rxerr)) return; /* txerr */ if(!ssl_printf(ssl, "%s%snum.txerr=%lu\n", n, d, (unsigned long)st->txerr)) return; /* number of requested-axfr, number of times axfr served to clients */ if(!ssl_printf(ssl, "%s%snum.raxfr=%lu\n", n, d, (unsigned long)st->raxfr)) return; /* truncated */ if(!ssl_printf(ssl, "%s%snum.truncated=%lu\n", n, d, (unsigned long)st->truncated)) return; /* dropped */ if(!ssl_printf(ssl, "%s%snum.dropped=%lu\n", n, d, (unsigned long)st->dropped)) return; } #ifdef USE_ZONE_STATS static void resize_zonestat(xfrd_state_type* xfrd, size_t num) { struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*)); if(xfrd->zonestat_clear_num != 0) memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num * sizeof(struct nsdst*)); free(xfrd->zonestat_clear); xfrd->zonestat_clear = a; xfrd->zonestat_clear_num = num; } static void zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear) { struct zonestatname* n; struct nsdst stat0, stat1; RBTREE_FOR(n, struct zonestatname*, xfrd->nsd->options->zonestatnames){ char* name = (char*)n->node.key; if(n->id >= xfrd->zonestat_safe) continue; /* newly allocated and reload has not yet done and replied with new size */ if(name == NULL || name[0]==0) continue; /* empty name, do not output */ /* the statistics are stored in two blocks, during reload * the newly forked processes get the other block to use, * these blocks are mmapped and are currently in use to * add statistics to */ memcpy(&stat0, &xfrd->nsd->zonestat[0][n->id], sizeof(stat0)); memcpy(&stat1, &xfrd->nsd->zonestat[1][n->id], sizeof(stat1)); stats_add(&stat0, &stat1); /* save a copy of current (cumulative) stats in stat1 */ memcpy(&stat1, &stat0, sizeof(stat1)); /* subtract last total of stats that was 'cleared' */ if(n->id < xfrd->zonestat_clear_num && xfrd->zonestat_clear[n->id]) stats_subtract(&stat0, xfrd->zonestat_clear[n->id]); if(clear) { /* extend storage array if needed */ if(n->id >= xfrd->zonestat_clear_num) { if(n->id+1 < xfrd->nsd->options->zonestatnames->count) resize_zonestat(xfrd, xfrd->nsd->options->zonestatnames->count); else resize_zonestat(xfrd, n->id+1); } if(!xfrd->zonestat_clear[n->id]) xfrd->zonestat_clear[n->id] = xalloc( sizeof(struct nsdst)); /* store last total of stats */ memcpy(xfrd->zonestat_clear[n->id], &stat1, sizeof(struct nsdst)); } /* stat0 contains the details that we want to print */ if(!ssl_printf(ssl, "%s%snum.queries=%lu\n", name, ".", (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + stat0.ctcp6))) return; print_stat_block(ssl, name, ".", &stat0); } } #endif /* USE_ZONE_STATS */ static void print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) { size_t i; stc_type total = 0; struct timeval elapsed, uptime; /* per CPU and total */ for(i=0; insd->child_count; i++) { if(!ssl_printf(ssl, "server%d.queries=%lu\n", (int)i, (unsigned long)xfrd->nsd->children[i].query_count)) return; total += xfrd->nsd->children[i].query_count; } if(!ssl_printf(ssl, "num.queries=%lu\n", (unsigned long)total)) return; /* time elapsed and uptime (in seconds) */ timeval_subtract(&uptime, now, &xfrd->nsd->rc->boot_time); timeval_subtract(&elapsed, now, &xfrd->nsd->rc->stats_time); if(!ssl_printf(ssl, "time.boot=%lu.%6.6lu\n", (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec)) return; if(!ssl_printf(ssl, "time.elapsed=%lu.%6.6lu\n", (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec)) return; /* mem info, database on disksize */ if(!print_longnum(ssl, "size.db.disk=", xfrd->nsd->st.db_disk)) return; if(!print_longnum(ssl, "size.db.mem=", xfrd->nsd->st.db_mem)) return; if(!print_longnum(ssl, "size.xfrd.mem=", region_get_mem(xfrd->region))) return; if(!print_longnum(ssl, "size.config.disk=", xfrd->nsd->options->zonelist_off)) return; if(!print_longnum(ssl, "size.config.mem=", region_get_mem( xfrd->nsd->options->region))) return; print_stat_block(ssl, "", "", &xfrd->nsd->st); /* zone statistics */ if(!ssl_printf(ssl, "zone.master=%lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) return; if(!ssl_printf(ssl, "zone.slave=%lu\n", (unsigned long)xfrd->zones->count)) return; #ifdef USE_ZONE_STATS zonestat_print(ssl, xfrd, clear); /* per-zone statistics */ #else (void)clear; #endif } static void clear_stats(xfrd_state_type* xfrd) { size_t i; uint64_t dbd = xfrd->nsd->st.db_disk; uint64_t dbm = xfrd->nsd->st.db_mem; for(i=0; insd->child_count; i++) { xfrd->nsd->children[i].query_count = 0; } memset(&xfrd->nsd->st, 0, sizeof(struct nsdst)); /* zonestats are cleared by storing the cumulative value that * was last printed in the zonestat_clear array, and subtracting * that before the next stats printout */ xfrd->nsd->st.db_disk = dbd; xfrd->nsd->st.db_mem = dbm; } void daemon_remote_process_stats(struct daemon_remote* rc) { RES res; struct rc_state* s; struct timeval now; if(!rc) return; if(gettimeofday(&now, NULL) == -1) log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); /* pop one and give it stats */ while((s = rc->stats_list)) { assert(s->in_stats_list); res.ssl = s->ssl; res.fd = s->fd; print_stats(&res, rc->xfrd, &now, (s->in_stats_list == 1)); if(s->in_stats_list == 1) { clear_stats(rc->xfrd); rc->stats_time = now; } VERBOSITY(3, (LOG_INFO, "remote control stats printed")); rc->stats_list = s->next; s->in_stats_list = 0; clean_point(rc, s); } } #endif /* BIND8_STATS */ int create_local_accept_sock(const char *path, int* noproto) { #ifdef HAVE_SYS_UN_H int s; struct sockaddr_un usock; VERBOSITY(3, (LOG_INFO, "creating unix socket %s", path)); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* this member exists on BSDs, not Linux */ usock.sun_len = (unsigned)sizeof(usock); #endif usock.sun_family = AF_LOCAL; /* length is 92-108, 104 on FreeBSD */ (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path)); if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { log_msg(LOG_ERR, "Cannot create local socket %s (%s)", path, strerror(errno)); return -1; } if (unlink(path) && errno != ENOENT) { /* The socket already exists and cannot be removed */ log_msg(LOG_ERR, "Cannot remove old local socket %s (%s)", path, strerror(errno)); goto err; } if (bind(s, (struct sockaddr *)&usock, (socklen_t)sizeof(struct sockaddr_un)) == -1) { log_msg(LOG_ERR, "Cannot bind local socket %s (%s)", path, strerror(errno)); goto err; } if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "Cannot set non-blocking mode"); goto err; } if (listen(s, TCP_BACKLOG) == -1) { log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); goto err; } (void)noproto; /*unused*/ return s; err: close(s); return -1; #else (void)path; log_msg(LOG_ERR, "Local sockets are not supported"); *noproto = 1; return -1; #endif } #endif /* HAVE_SSL */ nsd-4.1.26/options.c0000664000175000017500000015740213355422740013703 0ustar wouterwouter/* * options.c -- options functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include "options.h" #include "query.h" #include "tsig.h" #include "difffile.h" #include "rrl.h" #include "configyyrename.h" #include "configparser.h" config_parser_state_type* cfg_parser = 0; extern FILE* c_in, *c_out; int c_parse(void); int c_lex(void); int c_wrap(void); int c_lex_destroy(void); void c_error(const char *message); extern char* c_text; static int rbtree_strcmp(const void* p1, const void* p2) { if(p1 == NULL && p2 == NULL) return 0; if(p1 == NULL) return -1; if(p2 == NULL) return 1; return strcmp((const char*)p1, (const char*)p2); } struct nsd_options* nsd_options_create(region_type* region) { struct nsd_options* opt; opt = (struct nsd_options*)region_alloc(region, sizeof( struct nsd_options)); opt->region = region; opt->zone_options = rbtree_create(region, (int (*)(const void *, const void *)) dname_compare); opt->configfile = NULL; opt->zonestatnames = rbtree_create(opt->region, rbtree_strcmp); opt->patterns = rbtree_create(region, rbtree_strcmp); opt->keys = rbtree_create(region, rbtree_strcmp); opt->ip_addresses = NULL; opt->ip_transparent = 0; opt->ip_freebind = 0; opt->debug_mode = 0; opt->verbosity = 0; opt->hide_version = 0; opt->do_ip4 = 1; opt->do_ip6 = 1; opt->database = DBFILE; opt->identity = 0; opt->version = 0; opt->nsid = 0; opt->logfile = 0; opt->log_time_ascii = 1; opt->round_robin = 0; /* also packet.h::round_robin */ opt->minimal_responses = 0; /* also packet.h::minimal_responses */ opt->refuse_any = 0; opt->server_count = 1; opt->tcp_count = 100; opt->tcp_query_count = 0; opt->tcp_timeout = TCP_TIMEOUT; opt->tcp_mss = 0; opt->outgoing_tcp_mss = 0; opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN; opt->ipv6_edns_size = EDNS_MAX_MESSAGE_LEN; opt->pidfile = PIDFILE; opt->port = UDP_PORT; /* deprecated? opt->port = TCP_PORT; */ opt->reuseport = 0; opt->statistics = 0; opt->chroot = 0; opt->username = USER; opt->zonesdir = ZONESDIR; opt->xfrdfile = XFRDFILE; opt->xfrdir = XFRDIR; opt->zonelistfile = ZONELISTFILE; #ifdef RATELIMIT opt->rrl_size = RRL_BUCKETS; opt->rrl_slip = RRL_SLIP; opt->rrl_ipv4_prefix_length = RRL_IPV4_PREFIX_LENGTH; opt->rrl_ipv6_prefix_length = RRL_IPV6_PREFIX_LENGTH; # ifdef RATELIMIT_DEFAULT_OFF opt->rrl_ratelimit = 0; opt->rrl_whitelist_ratelimit = 0; # else opt->rrl_ratelimit = RRL_LIMIT/2; opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT/2; # endif #endif #ifdef USE_DNSTAP opt->dnstap_enable = 0; opt->dnstap_socket_path = DNSTAP_SOCKET_PATH; opt->dnstap_send_identity = 0; opt->dnstap_send_version = 0; opt->dnstap_identity = NULL; opt->dnstap_version = NULL; opt->dnstap_log_auth_query_messages = 0; opt->dnstap_log_auth_response_messages = 0; #endif opt->zonefiles_check = 1; if(opt->database == NULL || opt->database[0] == 0) opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; else opt->zonefiles_write = 0; opt->xfrd_reload_timeout = 1; opt->control_enable = 0; opt->control_interface = NULL; opt->control_port = NSD_CONTROL_PORT; opt->server_key_file = CONFIGDIR"/nsd_server.key"; opt->server_cert_file = CONFIGDIR"/nsd_server.pem"; opt->control_key_file = CONFIGDIR"/nsd_control.key"; opt->control_cert_file = CONFIGDIR"/nsd_control.pem"; return opt; } int nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone) { /* create dname for lookup */ const dname_type* dname = dname_parse(opt->region, zone->name); if(!dname) return 0; zone->node.key = dname; if(!rbtree_insert(opt->zone_options, (rbnode_type*)zone)) return 0; return 1; } int nsd_options_insert_pattern(struct nsd_options* opt, struct pattern_options* pat) { if(!pat->pname) return 0; pat->node.key = pat->pname; if(!rbtree_insert(opt->patterns, (rbnode_type*)pat)) return 0; return 1; } int parse_options_file(struct nsd_options* opt, const char* file, void (*err)(void*,const char*), void* err_arg) { FILE *in = 0; struct pattern_options* pat; struct acl_options* acl; if(!cfg_parser) { cfg_parser = (config_parser_state_type*)region_alloc( opt->region, sizeof(config_parser_state_type)); cfg_parser->chroot = 0; } cfg_parser->err = err; cfg_parser->err_arg = err_arg; cfg_parser->filename = (char*)file; cfg_parser->line = 1; cfg_parser->errors = 0; cfg_parser->server_settings_seen = 0; cfg_parser->opt = opt; cfg_parser->current_pattern = 0; cfg_parser->current_zone = 0; cfg_parser->current_key = 0; cfg_parser->current_ip_address_option = opt->ip_addresses; while(cfg_parser->current_ip_address_option && cfg_parser->current_ip_address_option->next) cfg_parser->current_ip_address_option = cfg_parser->current_ip_address_option->next; cfg_parser->current_allow_notify = 0; cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; in = fopen(cfg_parser->filename, "r"); if(!in) { if(err) { char m[MAXSYSLOGMSGLEN]; snprintf(m, sizeof(m), "Could not open %s: %s\n", file, strerror(errno)); err(err_arg, m); } else { fprintf(stderr, "Could not open %s: %s\n", file, strerror(errno)); } return 0; } c_in = in; c_parse(); fclose(in); opt->configfile = region_strdup(opt->region, file); if(cfg_parser->current_pattern) { if(!cfg_parser->current_pattern->pname) c_error("last pattern has no name"); else { if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->current_pattern)) c_error("duplicate pattern"); } } if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("last zone has no name"); else { if(!nsd_options_insert_zone(opt, cfg_parser->current_zone)) c_error("duplicate zone"); } if(!cfg_parser->current_zone->pattern) c_error("last zone has no pattern"); } if(cfg_parser->current_key) { if(!cfg_parser->current_key->name) c_error("last key has no name"); if(!cfg_parser->current_key->algorithm) c_error("last key has no algorithm"); if(!cfg_parser->current_key->secret) c_error("last key has no secret blob"); key_options_insert(opt, cfg_parser->current_key); } RBTREE_FOR(pat, struct pattern_options*, opt->patterns) { /* lookup keys for acls */ for(acl=pat->allow_notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error_msg("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error_msg("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->request_xfr; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error_msg("key %s in pattern %s could not be found", acl->key_name, pat->pname); } for(acl=pat->provide_xfr; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) c_error_msg("key %s in pattern %s could not be found", acl->key_name, pat->pname); } } if(cfg_parser->errors > 0) { if(err) { char m[MAXSYSLOGMSGLEN]; snprintf(m, sizeof(m), "read %s failed: %d errors in " "configuration file\n", file, cfg_parser->errors); err(err_arg, m); } else { fprintf(stderr, "read %s failed: %d errors in " "configuration file\n", file, cfg_parser->errors); } return 0; } return 1; } void options_zonestatnames_create(struct nsd_options* opt) { struct zone_options* zopt; /* allocate "" as zonestat 0, for zones without a zonestat */ if(!rbtree_search(opt->zonestatnames, "")) { struct zonestatname* n; n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n)); n->node.key = region_strdup(opt->region, ""); if(!n->node.key) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } n->id = (unsigned)(opt->zonestatnames->count); rbtree_insert(opt->zonestatnames, (rbnode_type*)n); } RBTREE_FOR(zopt, struct zone_options*, opt->zone_options) { /* insert into tree, so that when read in later id exists */ (void)getzonestatid(opt, zopt); } } #define ZONELIST_HEADER "# NSD zone list\n# name pattern\n" static int comp_zonebucket(const void* a, const void* b) { /* the line size is much smaller than max-int, and positive, * so the subtraction works */ return *(const int*)b - *(const int*)a; } /* insert free entry into zonelist free buckets */ static void zone_list_free_insert(struct nsd_options* opt, int linesize, off_t off) { struct zonelist_free* e; struct zonelist_bucket* b = (struct zonelist_bucket*)rbtree_search( opt->zonefree, &linesize); if(!b) { b = region_alloc_zero(opt->region, sizeof(*b)); b->linesize = linesize; b->node = *RBTREE_NULL; b->node.key = &b->linesize; rbtree_insert(opt->zonefree, &b->node); } e = (struct zonelist_free*)region_alloc_zero(opt->region, sizeof(*e)); e->next = b->list; b->list = e; e->off = off; opt->zonefree_number++; } struct zone_options* zone_list_zone_insert(struct nsd_options* opt, const char* nm, const char* patnm, int linesize, off_t off) { struct pattern_options* pat = pattern_options_find(opt, patnm); struct zone_options* zone; if(!pat) { log_msg(LOG_ERR, "pattern does not exist for zone %s " "pattern %s", nm, patnm); return NULL; } zone = zone_options_create(opt->region); zone->part_of_config = 0; zone->name = region_strdup(opt->region, nm); zone->linesize = linesize; zone->off = off; zone->pattern = pat; if(!nsd_options_insert_zone(opt, zone)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", nm, patnm); region_recycle(opt->region, (void*)zone->name, strlen(nm)+1); region_recycle(opt->region, zone, sizeof(*zone)); return NULL; } return zone; } int parse_zone_list_file(struct nsd_options* opt) { /* zonelist looks like this: # name pattern add example.com master del example.net slave add foo.bar.nl slave add rutabaga.uk config */ char buf[1024]; /* create empty data structures */ opt->zonefree = rbtree_create(opt->region, comp_zonebucket); opt->zonelist = NULL; opt->zonefree_number = 0; opt->zonelist_off = 0; /* try to open the zonelist file, an empty or nonexist file is OK */ opt->zonelist = fopen(opt->zonelistfile, "r+"); if(!opt->zonelist) { if(errno == ENOENT) return 1; /* file does not exist, it is created later */ log_msg(LOG_ERR, "could not open zone list %s: %s", opt->zonelistfile, strerror(errno)); return 0; } /* read header */ buf[strlen(ZONELIST_HEADER)] = 0; if(fread(buf, 1, strlen(ZONELIST_HEADER), opt->zonelist) != strlen(ZONELIST_HEADER) || strncmp(buf, ZONELIST_HEADER, strlen(ZONELIST_HEADER)) != 0) { log_msg(LOG_ERR, "zone list %s contains bad header\n", opt->zonelistfile); fclose(opt->zonelist); opt->zonelist = NULL; return 0; } /* read entries in file */ while(fgets(buf, sizeof(buf), opt->zonelist)) { /* skip comments and empty lines */ if(buf[0] == 0 || buf[0] == '\n' || buf[0] == '#') continue; if(strncmp(buf, "add ", 4) == 0) { int linesize = strlen(buf); /* parse the 'add' line */ /* pick last space on the line, so that the domain * name can have a space in it (but not the pattern)*/ char* space = strrchr(buf+4, ' '); char* nm, *patnm; if(!space) { /* parse error */ log_msg(LOG_ERR, "parse error in %s: '%s'", opt->zonelistfile, buf); continue; } nm = buf+4; *space = 0; patnm = space+1; if(linesize && buf[linesize-1] == '\n') buf[linesize-1] = 0; /* store offset and line size for zone entry */ /* and create zone entry in zonetree */ (void)zone_list_zone_insert(opt, nm, patnm, linesize, ftello(opt->zonelist)-linesize); } else if(strncmp(buf, "del ", 4) == 0) { /* store offset and line size for deleted entry */ int linesize = strlen(buf); zone_list_free_insert(opt, linesize, ftello(opt->zonelist)-linesize); } else { log_msg(LOG_WARNING, "bad data in %s, '%s'", opt->zonelistfile, buf); } } /* store EOF offset */ opt->zonelist_off = ftello(opt->zonelist); return 1; } void zone_options_delete(struct nsd_options* opt, struct zone_options* zone) { rbtree_delete(opt->zone_options, zone->node.key); region_recycle(opt->region, (void*)zone->node.key, dname_total_size( (dname_type*)zone->node.key)); region_recycle(opt->region, zone, sizeof(*zone)); } /* add a new zone to the zonelist */ struct zone_options* zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) { int r; struct zonelist_free* e; struct zonelist_bucket* b; int linesize = 6 + strlen(zname) + strlen(pname); /* create zone entry */ struct zone_options* zone = zone_list_zone_insert(opt, zname, pname, linesize, 0); if(!zone) return NULL; /* use free entry or append to file or create new file */ if(!opt->zonelist || opt->zonelist_off == 0) { /* create new file */ if(opt->zonelist) fclose(opt->zonelist); opt->zonelist = fopen(opt->zonelistfile, "w+"); if(!opt->zonelist) { log_msg(LOG_ERR, "could not create zone list %s: %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, ZONELIST_HEADER); if(r != strlen(ZONELIST_HEADER)) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } zone->off = ftello(opt->zonelist); if(zone->off == -1) log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } opt->zonelist_off = ftello(opt->zonelist); if(opt->zonelist_off == -1) log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } return zone; } b = (struct zonelist_bucket*)rbtree_search(opt->zonefree, &zone->linesize); if(!b || b->list == NULL) { /* no empty place, append to file */ zone->off = opt->zonelist_off; if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } opt->zonelist_off += linesize; if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } return zone; } /* reuse empty spot */ e = b->list; zone->off = e->off; if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", opt->zonelistfile, strerror(errno)); else log_msg(LOG_ERR, "partial write to %s: disk full", opt->zonelistfile); log_msg(LOG_ERR, "zone %s could not be added", zname); zone_options_delete(opt, zone); return NULL; } if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } /* snip off and recycle element */ b->list = e->next; region_recycle(opt->region, e, sizeof(*e)); if(b->list == NULL) { rbtree_delete(opt->zonefree, &b->linesize); region_recycle(opt->region, b, sizeof(*b)); } opt->zonefree_number--; return zone; } /* remove a zone on the zonelist */ void zone_list_del(struct nsd_options* opt, struct zone_options* zone) { /* put its space onto the free entry */ if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); return; } fprintf(opt->zonelist, "del"); zone_list_free_insert(opt, zone->linesize, zone->off); /* remove zone_options */ zone_options_delete(opt, zone); /* see if we need to compact: it is going to halve the zonelist */ if(opt->zonefree_number > opt->zone_options->count) { zone_list_compact(opt); } else { if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } } } /* postorder delete of zonelist free space tree */ static void delbucket(region_type* region, struct zonelist_bucket* b) { struct zonelist_free* e, *f; if(!b || (rbnode_type*)b==RBTREE_NULL) return; delbucket(region, (struct zonelist_bucket*)b->node.left); delbucket(region, (struct zonelist_bucket*)b->node.right); e = b->list; while(e) { f = e->next; region_recycle(region, e, sizeof(*e)); e = f; } region_recycle(region, b, sizeof(*b)); } /* compact zonelist file */ void zone_list_compact(struct nsd_options* opt) { char outname[1024]; FILE* out; struct zone_options* zone; off_t off; int r; snprintf(outname, sizeof(outname), "%s~", opt->zonelistfile); /* useful, when : count-of-free > count-of-used */ /* write zonelist to zonelist~ */ out = fopen(outname, "w+"); if(!out) { log_msg(LOG_ERR, "could not open %s: %s", outname, strerror(errno)); return; } r = fprintf(out, ZONELIST_HEADER); if(r == -1) { log_msg(LOG_ERR, "write %s failed: %s", outname, strerror(errno)); fclose(out); return; } else if(r != strlen(ZONELIST_HEADER)) { log_msg(LOG_ERR, "write %s was partial: disk full", outname); fclose(out); return; } off = ftello(out); if(off == -1) { log_msg(LOG_ERR, "ftello(%s): %s", outname, strerror(errno)); fclose(out); return; } RBTREE_FOR(zone, struct zone_options*, opt->zone_options) { if(zone->part_of_config) continue; r = fprintf(out, "add %s %s\n", zone->name, zone->pattern->pname); if(r < 0) { log_msg(LOG_ERR, "write %s failed: %s", outname, strerror(errno)); fclose(out); return; } else if(r != zone->linesize) { log_msg(LOG_ERR, "write %s was partial: disk full", outname); fclose(out); return; } } if(fflush(out) != 0) { log_msg(LOG_ERR, "fflush %s: %s", outname, strerror(errno)); } /* rename zonelist~ onto zonelist */ if(rename(outname, opt->zonelistfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", outname, opt->zonelistfile, strerror(errno)); fclose(out); return; } fclose(opt->zonelist); /* set offsets */ RBTREE_FOR(zone, struct zone_options*, opt->zone_options) { if(zone->part_of_config) continue; zone->off = off; off += zone->linesize; } /* empty the free tree */ delbucket(opt->region, (struct zonelist_bucket*)opt->zonefree->root); opt->zonefree->root = RBTREE_NULL; opt->zonefree->count = 0; opt->zonefree_number = 0; /* finish */ opt->zonelist = out; opt->zonelist_off = off; } /* close zonelist file */ void zone_list_close(struct nsd_options* opt) { if(opt->zonelist) { fclose(opt->zonelist); opt->zonelist = NULL; } } void c_error_va_list_pos(int showpos, const char* fmt, va_list args) { char* at = NULL; cfg_parser->errors++; if(showpos && c_text && c_text[0]!=0) { at = c_text; } if(cfg_parser->err) { char m[MAXSYSLOGMSGLEN]; snprintf(m, sizeof(m), "%s:%d: ", cfg_parser->filename, cfg_parser->line); (*cfg_parser->err)(cfg_parser->err_arg, m); if(at) { snprintf(m, sizeof(m), "at '%s': ", at); (*cfg_parser->err)(cfg_parser->err_arg, m); } (*cfg_parser->err)(cfg_parser->err_arg, "error: "); vsnprintf(m, sizeof(m), fmt, args); (*cfg_parser->err)(cfg_parser->err_arg, m); (*cfg_parser->err)(cfg_parser->err_arg, "\n"); return; } fprintf(stderr, "%s:%d: ", cfg_parser->filename, cfg_parser->line); if(at) fprintf(stderr, "at '%s': ", at); fprintf(stderr, "error: "); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } void c_error_msg_pos(int showpos, const char* fmt, ...) { va_list args; va_start(args, fmt); c_error_va_list_pos(showpos, fmt, args); va_end(args); } void c_error_msg(const char* fmt, ...) { va_list args; va_start(args, fmt); c_error_va_list_pos(0, fmt, args); va_end(args); } void c_error(const char* str) { if((strcmp(str, "syntax error")==0 || strcmp(str, "parse error")==0)) c_error_msg_pos(1, "%s", str); else c_error_msg("%s", str); } int c_wrap() { return 1; } struct zone_options* zone_options_create(region_type* region) { struct zone_options* zone; zone = (struct zone_options*)region_alloc(region, sizeof( struct zone_options)); zone->node = *RBTREE_NULL; zone->name = 0; zone->pattern = 0; zone->part_of_config = 0; return zone; } /* true is booleans are the same truth value */ #define booleq(x,y) ( ((x) && (y)) || (!(x) && !(y)) ) int acl_equal(struct acl_options* p, struct acl_options* q) { if(!booleq(p->use_axfr_only, q->use_axfr_only)) return 0; if(!booleq(p->allow_udp, q->allow_udp)) return 0; if(strcmp(p->ip_address_spec, q->ip_address_spec)!=0) return 0; /* the ip6, port, addr, mask, type: are derived from the ip_address_spec */ if(!booleq(p->nokey, q->nokey)) return 0; if(!booleq(p->blocked, q->blocked)) return 0; if(p->key_name && q->key_name) { if(strcmp(p->key_name, q->key_name)!=0) return 0; } else if(p->key_name && !q->key_name) return 0; else if(!p->key_name && q->key_name) return 0; /* key_options is derived from key_name */ return 1; } int acl_list_equal(struct acl_options* p, struct acl_options* q) { /* must be same and in same order */ while(p && q) { if(!acl_equal(p, q)) return 0; p = p->next; q = q->next; } if(!p && !q) return 1; /* different lengths */ return 0; } struct pattern_options* pattern_options_create(region_type* region) { struct pattern_options* p; p = (struct pattern_options*)region_alloc(region, sizeof( struct pattern_options)); p->node = *RBTREE_NULL; p->pname = 0; p->zonefile = 0; p->zonestats = 0; p->allow_notify = 0; p->request_xfr = 0; p->size_limit_xfr = 0; p->notify = 0; p->provide_xfr = 0; p->outgoing_interface = 0; p->notify_retry = 5; p->notify_retry_is_default = 1; p->allow_axfr_fallback = 1; p->allow_axfr_fallback_is_default = 1; p->implicit = 0; p->xfrd_flags = 0; p->max_refresh_time = 2419200; /* 4 weeks */ p->max_refresh_time_is_default = 1; p->min_refresh_time = 0; p->min_refresh_time_is_default = 1; p->max_retry_time = 1209600; /* 2 weeks */ p->max_retry_time_is_default = 1; p->min_retry_time = 0; p->min_retry_time_is_default = 1; #ifdef RATELIMIT p->rrl_whitelist = 0; #endif p->multi_master_check = 0; return p; } static void acl_delete(region_type* region, struct acl_options* acl) { if(acl->ip_address_spec) region_recycle(region, (void*)acl->ip_address_spec, strlen(acl->ip_address_spec)+1); if(acl->key_name) region_recycle(region, (void*)acl->key_name, strlen(acl->key_name)+1); /* key_options is a convenience pointer, not owned by the acl */ region_recycle(region, acl, sizeof(*acl)); } static void acl_list_delete(region_type* region, struct acl_options* list) { struct acl_options* n; while(list) { n = list->next; acl_delete(region, list); list = n; } } void pattern_options_remove(struct nsd_options* opt, const char* name) { struct pattern_options* p = (struct pattern_options*)rbtree_delete( opt->patterns, name); /* delete p and its contents */ if (!p) return; if(p->pname) region_recycle(opt->region, (void*)p->pname, strlen(p->pname)+1); if(p->zonefile) region_recycle(opt->region, (void*)p->zonefile, strlen(p->zonefile)+1); if(p->zonestats) region_recycle(opt->region, (void*)p->zonestats, strlen(p->zonestats)+1); acl_list_delete(opt->region, p->allow_notify); acl_list_delete(opt->region, p->request_xfr); acl_list_delete(opt->region, p->notify); acl_list_delete(opt->region, p->provide_xfr); acl_list_delete(opt->region, p->outgoing_interface); region_recycle(opt->region, p, sizeof(struct pattern_options)); } static struct acl_options* copy_acl(region_type* region, struct acl_options* a) { struct acl_options* b; if(!a) return NULL; b = (struct acl_options*)region_alloc(region, sizeof(*b)); /* copy the whole lot */ *b = *a; /* fix the pointers */ if(a->ip_address_spec) b->ip_address_spec = region_strdup(region, a->ip_address_spec); if(a->key_name) b->key_name = region_strdup(region, a->key_name); b->next = NULL; b->key_options = NULL; return b; } static struct acl_options* copy_acl_list(struct nsd_options* opt, struct acl_options* a) { struct acl_options* b, *blast = NULL, *blist = NULL; while(a) { b = copy_acl(opt->region, a); /* fixup key_options */ if(b->key_name) b->key_options = key_options_find(opt, b->key_name); else b->key_options = NULL; /* link as last into list */ b->next = NULL; if(!blist) blist = b; else blast->next = b; blast = b; a = a->next; } return blist; } static void copy_changed_acl(struct nsd_options* opt, struct acl_options** orig, struct acl_options* anew) { if(!acl_list_equal(*orig, anew)) { acl_list_delete(opt->region, *orig); *orig = copy_acl_list(opt, anew); } } static void copy_pat_fixed(region_type* region, struct pattern_options* orig, struct pattern_options* p) { orig->allow_axfr_fallback = p->allow_axfr_fallback; orig->allow_axfr_fallback_is_default = p->allow_axfr_fallback_is_default; orig->notify_retry = p->notify_retry; orig->notify_retry_is_default = p->notify_retry_is_default; orig->implicit = p->implicit; if(p->zonefile) orig->zonefile = region_strdup(region, p->zonefile); else orig->zonefile = NULL; if(p->zonestats) orig->zonestats = region_strdup(region, p->zonestats); else orig->zonestats = NULL; orig->max_refresh_time = p->max_refresh_time; orig->max_refresh_time_is_default = p->max_refresh_time_is_default; orig->min_refresh_time = p->min_refresh_time; orig->min_refresh_time_is_default = p->min_refresh_time_is_default; orig->max_retry_time = p->max_retry_time; orig->max_retry_time_is_default = p->max_retry_time_is_default; orig->min_retry_time = p->min_retry_time; orig->min_retry_time_is_default = p->min_retry_time_is_default; #ifdef RATELIMIT orig->rrl_whitelist = p->rrl_whitelist; #endif orig->multi_master_check = p->multi_master_check; } void pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p) { struct pattern_options* orig = pattern_options_find(opt, p->pname); if(!orig) { /* needs to be copied to opt region */ orig = pattern_options_create(opt->region); orig->pname = region_strdup(opt->region, p->pname); copy_pat_fixed(opt->region, orig, p); orig->allow_notify = copy_acl_list(opt, p->allow_notify); orig->request_xfr = copy_acl_list(opt, p->request_xfr); orig->notify = copy_acl_list(opt, p->notify); orig->provide_xfr = copy_acl_list(opt, p->provide_xfr); orig->outgoing_interface = copy_acl_list(opt, p->outgoing_interface); nsd_options_insert_pattern(opt, orig); } else { /* modify in place so pointers stay valid (and copy into region). Do not touch unchanged acls. */ if(orig->zonefile) region_recycle(opt->region, (char*)orig->zonefile, strlen(orig->zonefile)+1); if(orig->zonestats) region_recycle(opt->region, (char*)orig->zonestats, strlen(orig->zonestats)+1); copy_pat_fixed(opt->region, orig, p); copy_changed_acl(opt, &orig->allow_notify, p->allow_notify); copy_changed_acl(opt, &orig->request_xfr, p->request_xfr); copy_changed_acl(opt, &orig->notify, p->notify); copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr); copy_changed_acl(opt, &orig->outgoing_interface, p->outgoing_interface); } } struct pattern_options* pattern_options_find(struct nsd_options* opt, const char* name) { return (struct pattern_options*)rbtree_search(opt->patterns, name); } int pattern_options_equal(struct pattern_options* p, struct pattern_options* q) { if(strcmp(p->pname, q->pname) != 0) return 0; if(!p->zonefile && q->zonefile) return 0; else if(p->zonefile && !q->zonefile) return 0; else if(p->zonefile && q->zonefile) { if(strcmp(p->zonefile, q->zonefile) != 0) return 0; } if(!p->zonestats && q->zonestats) return 0; else if(p->zonestats && !q->zonestats) return 0; else if(p->zonestats && q->zonestats) { if(strcmp(p->zonestats, q->zonestats) != 0) return 0; } if(!booleq(p->allow_axfr_fallback, q->allow_axfr_fallback)) return 0; if(!booleq(p->allow_axfr_fallback_is_default, q->allow_axfr_fallback_is_default)) return 0; if(p->notify_retry != q->notify_retry) return 0; if(!booleq(p->notify_retry_is_default, q->notify_retry_is_default)) return 0; if(!booleq(p->implicit, q->implicit)) return 0; if(!acl_list_equal(p->allow_notify, q->allow_notify)) return 0; if(!acl_list_equal(p->request_xfr, q->request_xfr)) return 0; if(!acl_list_equal(p->notify, q->notify)) return 0; if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0; if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface)) return 0; if(p->max_refresh_time != q->max_refresh_time) return 0; if(!booleq(p->max_refresh_time_is_default, q->max_refresh_time_is_default)) return 0; if(p->min_refresh_time != q->min_refresh_time) return 0; if(!booleq(p->min_refresh_time_is_default, q->min_refresh_time_is_default)) return 0; if(p->max_retry_time != q->max_retry_time) return 0; if(!booleq(p->max_retry_time_is_default, q->max_retry_time_is_default)) return 0; if(p->min_retry_time != q->min_retry_time) return 0; if(!booleq(p->min_retry_time_is_default, q->min_retry_time_is_default)) return 0; #ifdef RATELIMIT if(p->rrl_whitelist != q->rrl_whitelist) return 0; #endif if(!booleq(p->multi_master_check,q->multi_master_check)) return 0; if(p->size_limit_xfr != q->size_limit_xfr) return 0; return 1; } static void marshal_u8(struct buffer* b, uint8_t v) { buffer_reserve(b, 1); buffer_write_u8(b, v); } static uint8_t unmarshal_u8(struct buffer* b) { return buffer_read_u8(b); } static void marshal_u64(struct buffer* b, uint64_t v) { buffer_reserve(b, 8); buffer_write_u64(b, v); } static uint64_t unmarshal_u64(struct buffer* b) { return buffer_read_u64(b); } #ifdef RATELIMIT static void marshal_u16(struct buffer* b, uint16_t v) { buffer_reserve(b, 2); buffer_write_u16(b, v); } #endif #ifdef RATELIMIT static uint16_t unmarshal_u16(struct buffer* b) { return buffer_read_u16(b); } #endif static void marshal_u32(struct buffer* b, uint32_t v) { buffer_reserve(b, 4); buffer_write_u32(b, v); } static uint32_t unmarshal_u32(struct buffer* b) { return buffer_read_u32(b); } static void marshal_str(struct buffer* b, const char* s) { if(!s) marshal_u8(b, 0); else { size_t len = strlen(s); marshal_u8(b, 1); buffer_reserve(b, len+1); buffer_write(b, s, len+1); } } static char* unmarshal_str(region_type* r, struct buffer* b) { uint8_t nonnull = unmarshal_u8(b); if(nonnull) { char* result = region_strdup(r, (char*)buffer_current(b)); size_t len = strlen((char*)buffer_current(b)); buffer_skip(b, len+1); return result; } else return NULL; } static void marshal_acl(struct buffer* b, struct acl_options* acl) { buffer_reserve(b, sizeof(*acl)); buffer_write(b, acl, sizeof(*acl)); marshal_str(b, acl->ip_address_spec); marshal_str(b, acl->key_name); } static struct acl_options* unmarshal_acl(region_type* r, struct buffer* b) { struct acl_options* acl = (struct acl_options*)region_alloc(r, sizeof(*acl)); buffer_read(b, acl, sizeof(*acl)); acl->next = NULL; acl->key_options = NULL; acl->ip_address_spec = unmarshal_str(r, b); acl->key_name = unmarshal_str(r, b); return acl; } static void marshal_acl_list(struct buffer* b, struct acl_options* list) { while(list) { marshal_u8(b, 1); /* is there a next one marker */ marshal_acl(b, list); list = list->next; } marshal_u8(b, 0); /* end of list marker */ } static struct acl_options* unmarshal_acl_list(region_type* r, struct buffer* b) { struct acl_options* a, *last=NULL, *list=NULL; while(unmarshal_u8(b)) { a = unmarshal_acl(r, b); /* link in */ a->next = NULL; if(!list) list = a; else last->next = a; last = a; } return list; } void pattern_options_marshal(struct buffer* b, struct pattern_options* p) { marshal_str(b, p->pname); marshal_str(b, p->zonefile); marshal_str(b, p->zonestats); #ifdef RATELIMIT marshal_u16(b, p->rrl_whitelist); #endif marshal_u8(b, p->allow_axfr_fallback); marshal_u8(b, p->allow_axfr_fallback_is_default); marshal_u8(b, p->notify_retry); marshal_u8(b, p->notify_retry_is_default); marshal_u8(b, p->implicit); marshal_u64(b, p->size_limit_xfr); marshal_acl_list(b, p->allow_notify); marshal_acl_list(b, p->request_xfr); marshal_acl_list(b, p->notify); marshal_acl_list(b, p->provide_xfr); marshal_acl_list(b, p->outgoing_interface); marshal_u32(b, p->max_refresh_time); marshal_u8(b, p->max_refresh_time_is_default); marshal_u32(b, p->min_refresh_time); marshal_u8(b, p->min_refresh_time_is_default); marshal_u32(b, p->max_retry_time); marshal_u8(b, p->max_retry_time_is_default); marshal_u32(b, p->min_retry_time); marshal_u8(b, p->min_retry_time_is_default); marshal_u8(b, p->multi_master_check); } struct pattern_options* pattern_options_unmarshal(region_type* r, struct buffer* b) { struct pattern_options* p = pattern_options_create(r); p->pname = unmarshal_str(r, b); p->zonefile = unmarshal_str(r, b); p->zonestats = unmarshal_str(r, b); #ifdef RATELIMIT p->rrl_whitelist = unmarshal_u16(b); #endif p->allow_axfr_fallback = unmarshal_u8(b); p->allow_axfr_fallback_is_default = unmarshal_u8(b); p->notify_retry = unmarshal_u8(b); p->notify_retry_is_default = unmarshal_u8(b); p->implicit = unmarshal_u8(b); p->size_limit_xfr = unmarshal_u64(b); p->allow_notify = unmarshal_acl_list(r, b); p->request_xfr = unmarshal_acl_list(r, b); p->notify = unmarshal_acl_list(r, b); p->provide_xfr = unmarshal_acl_list(r, b); p->outgoing_interface = unmarshal_acl_list(r, b); p->max_refresh_time = unmarshal_u32(b); p->max_refresh_time_is_default = unmarshal_u8(b); p->min_refresh_time = unmarshal_u32(b); p->min_refresh_time_is_default = unmarshal_u8(b); p->max_retry_time = unmarshal_u32(b); p->max_retry_time_is_default = unmarshal_u8(b); p->min_retry_time = unmarshal_u32(b); p->min_retry_time_is_default = unmarshal_u8(b); p->multi_master_check = unmarshal_u8(b); return p; } struct key_options* key_options_create(region_type* region) { struct key_options* key; key = (struct key_options*)region_alloc_zero(region, sizeof(struct key_options)); return key; } void key_options_insert(struct nsd_options* opt, struct key_options* key) { if(!key->name) return; key->node.key = key->name; (void)rbtree_insert(opt->keys, &key->node); } struct key_options* key_options_find(struct nsd_options* opt, const char* name) { return (struct key_options*)rbtree_search(opt->keys, name); } /** remove tsig_key contents */ void key_options_desetup(region_type* region, struct key_options* key) { /* keep tsig_key pointer so that existing references keep valid */ if(!key->tsig_key) return; /* name stays the same */ if(key->tsig_key->data) { /* wipe secret! */ memset(key->tsig_key->data, 0xdd, key->tsig_key->size); region_recycle(region, key->tsig_key->data, key->tsig_key->size); key->tsig_key->data = NULL; key->tsig_key->size = 0; } } /** add tsig_key contents */ void key_options_setup(region_type* region, struct key_options* key) { uint8_t data[16384]; /* 16KB */ int size; if(!key->tsig_key) { /* create it */ key->tsig_key = (tsig_key_type *) region_alloc(region, sizeof(tsig_key_type)); /* create name */ key->tsig_key->name = dname_parse(region, key->name); if(!key->tsig_key->name) { log_msg(LOG_ERR, "Failed to parse tsig key name %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = 0; key->tsig_key->data = NULL; } size = b64_pton(key->secret, data, sizeof(data)); if(size == -1) { log_msg(LOG_ERR, "Failed to parse tsig key data %s", key->name); /* key and base64 were checked during syntax parse */ exit(1); } key->tsig_key->size = size; key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size); } void key_options_remove(struct nsd_options* opt, const char* name) { struct key_options* k = key_options_find(opt, name); if(!k) return; (void)rbtree_delete(opt->keys, name); if(k->name) region_recycle(opt->region, k->name, strlen(k->name)+1); if(k->algorithm) region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1); if(k->secret) { memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */ region_recycle(opt->region, k->secret, strlen(k->secret)+1); } if(k->tsig_key) { tsig_del_key(k->tsig_key); if(k->tsig_key->name) region_recycle(opt->region, (void*)k->tsig_key->name, dname_total_size(k->tsig_key->name)); key_options_desetup(opt->region, k); region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type)); } region_recycle(opt->region, k, sizeof(struct key_options)); } int key_options_equal(struct key_options* p, struct key_options* q) { return strcmp(p->name, q->name)==0 && strcmp(p->algorithm, q->algorithm)==0 && strcmp(p->secret, q->secret)==0; } void key_options_add_modify(struct nsd_options* opt, struct key_options* key) { struct key_options* orig = key_options_find(opt, key->name); if(!orig) { /* needs to be copied to opt region */ orig = key_options_create(opt->region); orig->name = region_strdup(opt->region, key->name); orig->algorithm = region_strdup(opt->region, key->algorithm); orig->secret = region_strdup(opt->region, key->secret); key_options_setup(opt->region, orig); tsig_add_key(orig->tsig_key); key_options_insert(opt, orig); } else { /* modify entries in existing key, and copy to opt region */ key_options_desetup(opt->region, orig); region_recycle(opt->region, orig->algorithm, strlen(orig->algorithm)+1); orig->algorithm = region_strdup(opt->region, key->algorithm); region_recycle(opt->region, orig->secret, strlen(orig->secret)+1); orig->secret = region_strdup(opt->region, key->secret); key_options_setup(opt->region, orig); } } int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason) { /* check each acl element. if 1 blocked element matches - return -1. if any element matches - return number. else return -1. */ int found_match = -1; int number = 0; struct acl_options* match = 0; if(reason) *reason = NULL; while(acl) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "testing acl %s %s", acl->ip_address_spec, acl->nokey?"NOKEY": (acl->blocked?"BLOCKED":acl->key_name))); if(acl_addr_matches(acl, q) && acl_key_matches(acl, q)) { if(!match) { match = acl; /* remember first match */ found_match=number; } if(acl->blocked) { if(reason) *reason = acl; return -1; } } number++; acl = acl->next; } if(reason) *reason = match; return found_match; } #ifdef INET6 int acl_addr_matches_ipv6host(struct acl_options* acl, struct sockaddr_storage* addr_storage, unsigned int port) { struct sockaddr_in6* addr = (struct sockaddr_in6*)addr_storage; if(acl->port != 0 && acl->port != port) return 0; switch(acl->rangetype) { case acl_range_mask: case acl_range_subnet: if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) return 0; break; case acl_range_minmax: if(!acl_addr_match_range((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) return 0; break; case acl_range_single: default: if(memcmp(&addr->sin6_addr, &acl->addr.addr6, sizeof(struct in6_addr)) != 0) return 0; break; } return 1; } #endif int acl_addr_matches_ipv4host(struct acl_options* acl, struct sockaddr_in* addr, unsigned int port) { if(acl->port != 0 && acl->port != port) return 0; switch(acl->rangetype) { case acl_range_mask: case acl_range_subnet: if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) return 0; break; case acl_range_minmax: if(!acl_addr_match_range((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) return 0; break; case acl_range_single: default: if(memcmp(&addr->sin_addr, &acl->addr.addr, sizeof(struct in_addr)) != 0) return 0; break; } return 1; } int acl_addr_matches_host(struct acl_options* acl, struct acl_options* host) { if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_storage* addr = (struct sockaddr_storage*)&host->addr; if(!host->is_ipv6) return 0; return acl_addr_matches_ipv6host(acl, addr, host->port); #else return 0; /* no inet6, no match */ #endif } else { struct sockaddr_in* addr = (struct sockaddr_in*)&host->addr; if(host->is_ipv6) return 0; return acl_addr_matches_ipv4host(acl, addr, host->port); } /* ENOTREACH */ return 0; } int acl_addr_matches(struct acl_options* acl, struct query* q) { if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->addr; if(addr->ss_family != AF_INET6) return 0; return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); #else return 0; /* no inet6, no match */ #endif } else { struct sockaddr_in* addr = (struct sockaddr_in*)&q->addr; if(addr->sin_family != AF_INET) return 0; return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); } /* ENOTREACH */ return 0; } int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz) { size_t i; #ifndef NDEBUG assert(sz % 4 == 0); #endif sz /= 4; for(i=0; i x[i]) return 0; if(checkmax) if(maxval[i] < x[i]) return 0; /* if x is equal to a bound, that bound needs further checks */ if(checkmin && minval[i]!=x[i]) checkmin = 0; if(checkmax && maxval[i]!=x[i]) checkmax = 0; if(!checkmin && !checkmax) return 1; /* will always match */ } return 1; } int acl_key_matches(struct acl_options* acl, struct query* q) { if(acl->blocked) return 1; if(acl->nokey) { if(q->tsig.status == TSIG_NOT_PRESENT) return 1; return 0; } /* check name of tsig key */ if(q->tsig.status != TSIG_OK) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail query has no TSIG")); return 0; /* query has no TSIG */ } if(q->tsig.error_code != TSIG_ERROR_NOERROR) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail, tsig has error")); return 0; /* some tsig error */ } if(!acl->key_options->tsig_key) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail no config")); return 0; /* key not properly configured */ } if(dname_compare(q->tsig.key_name, acl->key_options->tsig_key->name) != 0) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail wrong key name")); return 0; /* wrong key name */ } if(tsig_strlowercmp(q->tsig.algorithm->short_name, acl->key_options->algorithm) != 0 && ( strncmp("hmac-", q->tsig.algorithm->short_name, 5) != 0 || tsig_strlowercmp(q->tsig.algorithm->short_name+5, acl->key_options->algorithm) != 0) ) { DEBUG(DEBUG_XFRD,2, (LOG_ERR, "query tsig wrong algorithm")); return 0; /* no such algo */ } return 1; } int acl_same_host(struct acl_options* a, struct acl_options* b) { if(a->is_ipv6 && !b->is_ipv6) return 0; if(!a->is_ipv6 && b->is_ipv6) return 0; if(a->port != b->port) return 0; if(a->rangetype != b->rangetype) return 0; if(!a->is_ipv6) { if(memcmp(&a->addr.addr, &b->addr.addr, sizeof(struct in_addr)) != 0) return 0; if(a->rangetype != acl_range_single && memcmp(&a->range_mask.addr, &b->range_mask.addr, sizeof(struct in_addr)) != 0) return 0; } else { #ifdef INET6 if(memcmp(&a->addr.addr6, &b->addr.addr6, sizeof(struct in6_addr)) != 0) return 0; if(a->rangetype != acl_range_single && memcmp(&a->range_mask.addr6, &b->range_mask.addr6, sizeof(struct in6_addr)) != 0) return 0; #else return 0; #endif } return 1; } #if defined(HAVE_SSL) void key_options_tsig_add(struct nsd_options* opt) { struct key_options* optkey; RBTREE_FOR(optkey, struct key_options*, opt->keys) { key_options_setup(opt->region, optkey); tsig_add_key(optkey->tsig_key); } } #endif int zone_is_slave(struct zone_options* opt) { return opt && opt->pattern && opt->pattern->request_xfr != 0; } /* get a character in string (or replacement char if not long enough) */ static const char* get_char(const char* str, size_t i) { static char res[2]; if(i >= strlen(str)) return "."; res[0] = str[i]; res[1] = 0; return res; } /* get end label of the zone name (or .) */ static const char* get_end_label(struct zone_options* zone, int i) { const dname_type* d = (const dname_type*)zone->node.key; if(i >= d->label_count) { return "."; } return wirelabel2str(dname_label(d, i)); } /* replace occurrences of one with two */ void replace_str(char* str, size_t len, const char* one, const char* two) { char* pos; char* at = str; while( (pos=strstr(at, one)) ) { if(strlen(str)+strlen(two)-strlen(one) >= len) return; /* no more space to replace */ /* stuff before pos is fine */ /* move the stuff after pos to make space for two, add * one to length of remainder to also copy the 0 byte end */ memmove(pos+strlen(two), pos+strlen(one), strlen(pos+strlen(one))+1); /* copy in two */ memmove(pos, two, strlen(two)); /* at is end of the newly inserted two (avoids recursion if * two contains one) */ at = pos+strlen(two); } } const char* config_cook_string(struct zone_options* zone, const char* input) { static char f[1024]; /* if not a template, return as-is */ if(!strchr(input, '%')) { return input; } strlcpy(f, input, sizeof(f)); if(strstr(f, "%1")) replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); if(strstr(f, "%2")) replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); if(strstr(f, "%3")) replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); if(strstr(f, "%z")) replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); if(strstr(f, "%y")) replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); if(strstr(f, "%x")) replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); if(strstr(f, "%s")) replace_str(f, sizeof(f), "%s", zone->name); return f; } const char* config_make_zonefile(struct zone_options* zone, struct nsd* nsd) { static char f[1024]; /* if not a template, return as-is */ if(!strchr(zone->pattern->zonefile, '%')) { if (nsd->chrootdir && nsd->chrootdir[0] && zone->pattern->zonefile && zone->pattern->zonefile[0] == '/' && strncmp(zone->pattern->zonefile, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) /* -1 because chrootdir ends in trailing slash */ return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1; return zone->pattern->zonefile; } strlcpy(f, zone->pattern->zonefile, sizeof(f)); if(strstr(f, "%1")) replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); if(strstr(f, "%2")) replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); if(strstr(f, "%3")) replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); if(strstr(f, "%z")) replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); if(strstr(f, "%y")) replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); if(strstr(f, "%x")) replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); if(strstr(f, "%s")) replace_str(f, sizeof(f), "%s", zone->name); if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' && strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) /* -1 because chrootdir ends in trailing slash */ return f + strlen(nsd->chrootdir) - 1; return f; } struct zone_options* zone_options_find(struct nsd_options* opt, const struct dname* apex) { return (struct zone_options*) rbtree_search(opt->zone_options, apex); } struct acl_options* acl_find_num(struct acl_options* acl, int num) { int count = num; if(num < 0) return 0; while(acl && count > 0) { acl = acl->next; count--; } if(count == 0) return acl; return 0; } /* true if ipv6 address, false if ipv4 */ int parse_acl_is_ipv6(const char* p) { /* see if addr is ipv6 or ipv4 -- by : and . */ while(*p) { if(*p == '.') return 0; if(*p == ':') return 1; ++p; } return 0; } /* returns range type. mask is the 2nd part of the range */ int parse_acl_range_type(char* ip, char** mask) { char *p; if((p=strchr(ip, '&'))!=0) { *p = 0; *mask = p+1; return acl_range_mask; } if((p=strchr(ip, '/'))!=0) { *p = 0; *mask = p+1; return acl_range_subnet; } if((p=strchr(ip, '-'))!=0) { *p = 0; *mask = p+1; return acl_range_minmax; } *mask = 0; return acl_range_single; } /* parses subnet mask, fills 0 mask as well */ void parse_acl_range_subnet(char* p, void* addr, int maxbits) { int subnet_bits = atoi(p); uint8_t* addr_bytes = (uint8_t*)addr; if(subnet_bits == 0 && strcmp(p, "0")!=0) { c_error_msg("bad subnet range '%s'", p); return; } if(subnet_bits < 0 || subnet_bits > maxbits) { c_error_msg("subnet of %d bits out of range [0..%d]", subnet_bits, maxbits); return; } /* fill addr with n bits of 1s (struct has been zeroed) */ while(subnet_bits >= 8) { *addr_bytes++ = 0xff; subnet_bits -= 8; } if(subnet_bits > 0) { uint8_t shifts[] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; *addr_bytes = shifts[subnet_bits]; } } struct acl_options* parse_acl_info(region_type* region, char* ip, const char* key) { char* p; struct acl_options* acl = (struct acl_options*)region_alloc(region, sizeof(struct acl_options)); acl->next = 0; /* ip */ acl->ip_address_spec = region_strdup(region, ip); acl->use_axfr_only = 0; acl->allow_udp = 0; acl->ixfr_disabled = 0; acl->bad_xfr_count = 0; acl->key_options = 0; acl->is_ipv6 = 0; acl->port = 0; memset(&acl->addr, 0, sizeof(union acl_addr_storage)); memset(&acl->range_mask, 0, sizeof(union acl_addr_storage)); if((p=strrchr(ip, '@'))!=0) { if(atoi(p+1) == 0) c_error("expected port number after '@'"); else acl->port = atoi(p+1); *p=0; } acl->rangetype = parse_acl_range_type(ip, &p); if(parse_acl_is_ipv6(ip)) { acl->is_ipv6 = 1; #ifdef INET6 if(inet_pton(AF_INET6, ip, &acl->addr.addr6) != 1) c_error_msg("Bad ip6 address '%s'", ip); if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) { assert(p); if(inet_pton(AF_INET6, p, &acl->range_mask.addr6) != 1) c_error_msg("Bad ip6 address mask '%s'", p); } if(acl->rangetype==acl_range_subnet) { assert(p); parse_acl_range_subnet(p, &acl->range_mask.addr6, 128); } #else c_error_msg("encountered IPv6 address '%s'.", ip); #endif /* INET6 */ } else { acl->is_ipv6 = 0; if(inet_pton(AF_INET, ip, &acl->addr.addr) != 1) c_error_msg("Bad ip4 address '%s'", ip); if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) { assert(p); if(inet_pton(AF_INET, p, &acl->range_mask.addr) != 1) c_error_msg("Bad ip4 address mask '%s'", p); } if(acl->rangetype==acl_range_subnet) { assert(p); parse_acl_range_subnet(p, &acl->range_mask.addr, 32); } } /* key */ if(strcmp(key, "NOKEY")==0) { acl->nokey = 1; acl->blocked = 0; acl->key_name = 0; } else if(strcmp(key, "BLOCKED")==0) { acl->nokey = 0; acl->blocked = 1; acl->key_name = 0; } else { acl->nokey = 0; acl->blocked = 0; acl->key_name = region_strdup(region, key); } return acl; } /* copy acl list at end of parser start, update current */ static void append_acl(struct acl_options** start, struct acl_options** cur, struct acl_options* list) { while(list) { struct acl_options* acl = copy_acl(cfg_parser->opt->region, list); acl->next = NULL; if(*cur) (*cur)->next = acl; else *start = acl; *cur = acl; list = list->next; } } void config_apply_pattern(const char* name) { /* find the pattern */ struct pattern_options* pat = pattern_options_find(cfg_parser->opt, name); struct pattern_options* a = cfg_parser->current_pattern; if(!pat) { c_error_msg("could not find pattern %s", name); return; } /* apply settings */ if(pat->zonefile) a->zonefile = region_strdup(cfg_parser->opt->region, pat->zonefile); if(pat->zonestats) a->zonestats = region_strdup(cfg_parser->opt->region, pat->zonestats); if(!pat->allow_axfr_fallback_is_default) { a->allow_axfr_fallback = pat->allow_axfr_fallback; a->allow_axfr_fallback_is_default = 0; } if(!pat->notify_retry_is_default) { a->notify_retry = pat->notify_retry; a->notify_retry_is_default = 0; } if(!pat->max_refresh_time_is_default) { a->max_refresh_time = pat->max_refresh_time; a->max_refresh_time_is_default = 0; } if(!pat->min_refresh_time_is_default) { a->min_refresh_time = pat->min_refresh_time; a->min_refresh_time_is_default = 0; } if(!pat->max_retry_time_is_default) { a->max_retry_time = pat->max_retry_time; a->max_retry_time_is_default = 0; } if(!pat->min_retry_time_is_default) { a->min_retry_time = pat->min_retry_time; a->min_retry_time_is_default = 0; } a->size_limit_xfr = pat->size_limit_xfr; #ifdef RATELIMIT a->rrl_whitelist |= pat->rrl_whitelist; #endif /* append acl items */ append_acl(&a->allow_notify, &cfg_parser->current_allow_notify, pat->allow_notify); append_acl(&a->request_xfr, &cfg_parser->current_request_xfr, pat->request_xfr); append_acl(&a->notify, &cfg_parser->current_notify, pat->notify); append_acl(&a->provide_xfr, &cfg_parser->current_provide_xfr, pat->provide_xfr); append_acl(&a->outgoing_interface, &cfg_parser-> current_outgoing_interface, pat->outgoing_interface); if(pat->multi_master_check) a->multi_master_check = pat->multi_master_check; } void nsd_options_destroy(struct nsd_options* opt) { region_destroy(opt->region); #ifdef MEMCLEAN /* OS collects memory pages */ c_lex_destroy(); #endif } unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt) { #ifdef USE_ZONE_STATS const char* statname; struct zonestatname* n; rbnode_type* res; /* try to find the instantiated zonestat name */ if(!zopt->pattern->zonestats || zopt->pattern->zonestats[0]==0) return 0; /* no zone stats */ statname = config_cook_string(zopt, zopt->pattern->zonestats); res = rbtree_search(opt->zonestatnames, statname); if(res) return ((struct zonestatname*)res)->id; /* create it */ n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n)); n->node.key = region_strdup(opt->region, statname); if(!n->node.key) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } n->id = (unsigned)(opt->zonestatnames->count); rbtree_insert(opt->zonestatnames, (rbnode_type*)n); return n->id; #else /* USE_ZONE_STATS */ (void)opt; (void)zopt; return 0; #endif /* USE_ZONE_STATS */ } /** check if config turns on IP-address interface with certificates or a * named pipe without certificates. */ int options_remote_is_address(struct nsd_options* cfg) { if(!cfg->control_enable) return 0; if(!cfg->control_interface) return 1; if(!cfg->control_interface->address) return 1; if(cfg->control_interface->address[0] == 0) return 1; return (cfg->control_interface->address[0] != '/'); } nsd-4.1.26/Makefile.in0000664000175000017500000007441413355417226014115 0ustar wouterwouter# # Makefile -- one file to make them all, nsd(8) # # Copyright (c) 2001-2006, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # Standard installation pathnames SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ mandir = @mandir@ datarootdir = @datarootdir@ # NSD specific pathnames configdir = @configdir@ piddir = @piddir@ dbdir = @dbdir@ pidfile = @pidfile@ logfile = @logfile@ dbfile = @dbfile@ xfrdir = @xfrdir@ xfrdfile = @xfrdfile@ zonelistfile = @zonelistfile@ nsdconfigfile = @nsd_conf_file@ zonesdir = @zonesdir@ chrootdir= @chrootdir@ user = @user@ DNSTAP_SRC=@DNSTAP_SRC@ DNSTAP_OBJ=@DNSTAP_OBJ@ # override $U variable which is used by autotools for deansification (for # K&R C compilers), but causes problems if $U is defined in the env). U= CC = @CC@ CPPFLAGS = @CPPFLAGS@ CFLAGS = @CFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ SSL_LIBS = @SSL_LIBS@ LIBOBJS = @LIBOBJS@ INSTALL = $(srcdir)/install-sh -c INSTALL_PROGRAM = $(INSTALL) INSTALL_DATA = $(INSTALL) -m 644 YACC = @YACC@ LEX = @LEX@ PROTOC_C = @PROTOC_C@ COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) LINK = $(CC) $(CFLAGS) $(LDFLAGS) EDIT = sed \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix\@,$(exec_prefix),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@configdir\@,$(configdir),g' \ -e 's,@zonesdir\@,$(zonesdir),g' \ -e 's,@chrootdir\@,$(chrootdir),g' \ -e 's,@pidfile\@,$(pidfile),g' \ -e 's,@logfile\@,$(logfile),g' \ -e 's,@dbfile\@,$(dbfile),g' \ -e 's,@xfrdir\@,$(xfrdir),g' \ -e 's,@xfrdfile\@,$(xfrdfile),g' \ -e 's,@zonelistfile\@,$(zonelistfile),g' \ -e 's,@nsdconfigfile\@,$(nsdconfigfile),g' \ -e 's,@shell\@,$(SHELL),g' \ -e 's,@ratelimit_default\@,@ratelimit_default@,g' \ -e 's,@user\@,$(user),g' TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control-setup.sh MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 COMMON_OBJ=answer.o axfr.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o tsig.o tsig-openssl.o udb.o udbradtree.o udbzone.o util.o XFRD_OBJ=xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(DNSTAP_OBJ) NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zlexer.o zonec.o zparser.o ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o NSD_CHECKZONE_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o nsd-checkzone.o NSD_CONTROL_OBJ=$(COMMON_OBJ) nsd-control.o CUTEST_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o cutest_dname.o cutest_dns.o cutest_iterated_hash.o cutest_run.o cutest_radtree.o cutest_rbtree.o cutest_namedb.o cutest_options.o cutest_region.o cutest_rrl.o cutest_udb.o cutest_udbrad.o cutest_util.o cutest.o qtest.o NSD_MEM_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o nsd-mem.o all: $(TARGETS) $(MANUALS) $(ALL_OBJ): $(COMPILE) -c $< nsd-control-setup.sh: $(srcdir)/nsd-control-setup.sh.in config.h rm -f nsd-control-setup.sh $(EDIT) $(srcdir)/nsd-control-setup.sh.in > nsd-control-setup.sh chmod +x nsd-control-setup.sh nsd.conf.sample: $(srcdir)/nsd.conf.sample.in config.h rm -f nsd.conf.sample $(EDIT) $(srcdir)/nsd.conf.sample.in | awk '/RRLconfig'@ratelimit@'/ { while($$0 !~ /.*RRLend.*/) { getline; } getline; } {print} ' > nsd.conf.sample nsd.conf.5: $(srcdir)/nsd.conf.5.in config.h rm -f nsd.conf.5 $(EDIT) $(srcdir)/nsd.conf.5.in | awk '/rrlstart'@ratelimit@'/ { while($$0 !~ /.*rrlend.*/) { getline; } getline; } {print} ' > nsd.conf.5 nsd.8: $(srcdir)/nsd.8.in config.h rm -f nsd.8 $(EDIT) $(srcdir)/nsd.8.in > nsd.8 nsd-checkconf.8: $(srcdir)/nsd-checkconf.8.in config.h rm -f nsd-checkconf.8 $(EDIT) $(srcdir)/nsd-checkconf.8.in > nsd-checkconf.8 nsd-checkzone.8: $(srcdir)/nsd-checkzone.8.in config.h rm -f nsd-checkzone.8 $(EDIT) $(srcdir)/nsd-checkzone.8.in > nsd-checkzone.8 nsd-control.8: $(srcdir)/nsd-control.8.in config.h rm -f nsd-control.8 $(EDIT) $(srcdir)/nsd-control.8.in > nsd-control.8 install: all $(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) -d $(DESTDIR)$(configdir) $(INSTALL) -d $(DESTDIR)$(piddir) $(INSTALL) -d $(DESTDIR)$(xfrdir) $(INSTALL) -d $(DESTDIR)$(dbdir) $(INSTALL) -d $(DESTDIR)$(mandir) $(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(mandir)/man5 $(INSTALL) nsd $(DESTDIR)$(sbindir)/nsd $(INSTALL) nsd-control-setup.sh $(DESTDIR)$(sbindir)/nsd-control-setup $(INSTALL) nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkconf $(INSTALL) nsd-checkzone $(DESTDIR)$(sbindir)/nsd-checkzone $(INSTALL) nsd-control $(DESTDIR)$(sbindir)/nsd-control $(INSTALL_DATA) nsd.8 $(DESTDIR)$(mandir)/man8 $(INSTALL_DATA) nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(INSTALL_DATA) nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(INSTALL_DATA) nsd-control.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 $(INSTALL_DATA) nsd.conf.5 $(DESTDIR)$(mandir)/man5/nsd.conf.5 $(INSTALL_DATA) nsd.conf.sample $(DESTDIR)$(nsdconfigfile).sample uninstall: @echo rm -f -- $(DESTDIR)$(sbindir)/nsd $(DESTDIR)$(sbindir)/nsd-control-setup $(DESTDIR)$(sbindir)/nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkzone $(DESTDIR)$(sbindir)/nsd-control rm -f -- $(DESTDIR)$(mandir)/man8/nsd.8 $(DESTDIR)$(mandir)/man5/nsd.conf.5 rm -f -- $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 rm -f -- $(DESTDIR)$(pidfile) @echo @echo "You still need to remove $(DESTDIR)$(configdir), $(DESTDIR)$(piddir), $(DESTDIR)$(dbfile) directory by hand." test: nsd: $(NSD_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) nsd-checkconf: $(NSD_CHECKCONF_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CHECKCONF_OBJ) $(LIBOBJS) $(LIBS) nsd-checkzone: $(NSD_CHECKZONE_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CHECKZONE_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) nsd-control: $(NSD_CONTROL_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CONTROL_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) nsd-mem: $(NSD_MEM_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_MEM_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) cutest: $(CUTEST_OBJ) $(LIBOBJS) $(LINK) -o $@ $(CUTEST_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) udb-inspect: udb-inspect.o $(COMMON_OBJ) $(LIBOBJS) $(LINK) -o $@ udb-inspect.o $(COMMON_OBJ) $(LIBOBJS) $(LIBS) xfr-inspect: xfr-inspect.o $(COMMON_OBJ) $(LIBOBJS) $(LINK) -o $@ xfr-inspect.o $(COMMON_OBJ) $(LIBOBJS) $(LIBS) clean: rm -f *.o $(TARGETS) $(MANUALS) cutest udb-inspect xfr-inspect nsd-mem realclean: clean rm -f Makefile config.h config.log config.status rm -rf autom4te* rm -f zlexer.c zparser.h zparser.c zparser.stamp rm -f configlexer.c configparser.h configparser.c configparser.stamp devclean: realclean rm -f config.h.in configure basename.o: $(srcdir)/compat/basename.c $(COMPILE) -c $(srcdir)/compat/basename.c inet_pton.o: $(srcdir)/compat/inet_pton.c $(COMPILE) -c $(srcdir)/compat/inet_pton.c inet_ntop.o: $(srcdir)/compat/inet_ntop.c $(COMPILE) -c $(srcdir)/compat/inet_ntop.c inet_aton.o: $(srcdir)/compat/inet_aton.c $(COMPILE) -c $(srcdir)/compat/inet_aton.c b64_pton.o: $(srcdir)/compat/b64_pton.c $(COMPILE) -c $(srcdir)/compat/b64_pton.c b64_ntop.o: $(srcdir)/compat/b64_ntop.c $(COMPILE) -c $(srcdir)/compat/b64_ntop.c memcmp.o: $(srcdir)/compat/memcmp.c $(COMPILE) -c $(srcdir)/compat/memcmp.c memmove.o: $(srcdir)/compat/memmove.c $(COMPILE) -c $(srcdir)/compat/memmove.c snprintf.o: $(srcdir)/compat/snprintf.c $(COMPILE) -c $(srcdir)/compat/snprintf.c strlcat.o: $(srcdir)/compat/strlcat.c $(COMPILE) -c $(srcdir)/compat/strlcat.c strlcpy.o: $(srcdir)/compat/strlcpy.c $(COMPILE) -c $(srcdir)/compat/strlcpy.c strptime.o: $(srcdir)/compat/strptime.c $(COMPILE) -c $(srcdir)/compat/strptime.c vsnprintf.o: $(srcdir)/compat/vsnprintf.c $(COMPILE) -c $(srcdir)/compat/vsnprintf.c timegm.o: $(srcdir)/compat/timegm.c $(COMPILE) -c $(srcdir)/compat/timegm.c malloc.o: $(srcdir)/compat/malloc.c $(COMPILE) -c $(srcdir)/compat/malloc.c pselect.o: $(srcdir)/compat/pselect.c $(COMPILE) -c $(srcdir)/compat/pselect.c reallocarray.o: $(srcdir)/compat/reallocarray.c $(COMPILE) -c $(srcdir)/compat/reallocarray.c fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(COMPILE) -c $(srcdir)/compat/fake-rfc2553.c cutest_dname.o: $(srcdir)/tpkg/cutest/cutest_dname.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_dname.c cutest_dns.o: $(srcdir)/tpkg/cutest/cutest_dns.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_dns.c cutest_iterated_hash.o: $(srcdir)/tpkg/cutest/cutest_iterated_hash.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_iterated_hash.c cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_run.c cutest_rbtree.o: $(srcdir)/tpkg/cutest/cutest_rbtree.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_rbtree.c cutest_radtree.o: $(srcdir)/tpkg/cutest/cutest_radtree.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_radtree.c cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_namedb.c cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_options.c cutest_region.o: $(srcdir)/tpkg/cutest/cutest_region.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_region.c cutest_rrl.o: $(srcdir)/tpkg/cutest/cutest_rrl.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_rrl.c cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_udb.c cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_udbrad.c cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest_util.c cutest.o: $(srcdir)/tpkg/cutest/cutest.c $(COMPILE) -c $(srcdir)/tpkg/cutest/cutest.c qtest.o: $(srcdir)/tpkg/cutest/qtest.c $(COMPILE) -c $(srcdir)/tpkg/cutest/qtest.c udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c $(COMPILE) -c $(srcdir)/tpkg/cutest/udb-inspect.c zlexer.c: $(srcdir)/zlexer.lex if test "$(LEX)" != ":"; then rm -f $@ ;\ echo '#include "config.h"' > $@ ;\ $(LEX) -i -t $(srcdir)/zlexer.lex >> $@ ;\ fi @if test ! -f $@; then echo "No $@ : need flex and bison to compile from source repository"; exit 1; fi zparser.c zparser.h: $(srcdir)/zparser.y $(YACC) -d -o zparser.c $(srcdir)/zparser.y configlexer.c: $(srcdir)/configlexer.lex if test "$(LEX)" != ":"; then rm -f $@ ;\ echo '#include "configyyrename.h"' > $@ ;\ $(LEX) -i -t $(srcdir)/configlexer.lex >> $@ ;\ fi @if test ! -f $@; then echo "No $@ : need flex and bison to compile from source repository"; exit 1; fi configparser.c configparser.h: $(srcdir)/configparser.y $(YACC) -d -o configparser.c $(srcdir)/configparser.y # dnstap dnstap.o: $(srcdir)/dnstap/dnstap.c config.h \ dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h $(srcdir)/dnstap/dnstap.h \ $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h dnstap.pb-c.o: dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h dnstap_collector.o: $(srcdir)/dnstap/dnstap_collector.c config.h \ $(srcdir)/dnstap/dnstap.h $(srcdir)/dnstap/dnstap_collector.h \ $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/region-allocator.h \ $(srcdir)/buffer.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/options.h dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h: $(srcdir)/dnstap/dnstap.proto @-if test ! -d dnstap; then $(INSTALL) -d dnstap; fi $(PROTOC_C) --c_out=. --proto_path=$(srcdir) $(srcdir)/dnstap/dnstap.proto # autoconf rules config.h.in: configure.ac autoheader configure: configure.ac autoconf tags: ctags *.[ch] # dependency generation DEPEND_TMP=depend1073.tmp DEPEND_TMP2=depend1074.tmp DEPEND_TARGET=Makefile DEPEND_TARGET2=Makefile.in depend: (cd $(srcdir) ; $(CC) -MM $(CPPFLAGS) *.c compat/*.c `if test -d tpkg/cutest; then echo tpkg/cutest/*.c; fi`) | \ sed -e 's? *\([^ ]*\.[ch]\)? $$(srcdir)/\1?g' | \ sed -e 's?$$(srcdir)/config.h?config.h?g' \ -e 's?$$(srcdir)/configlexer.c?configlexer.c?g' \ -e 's?$$(srcdir)/configparser.c?configparser.c?g' \ -e 's?$$(srcdir)/configparser.h?configparser.h?g' \ -e 's?$$(srcdir)/zlexer.c?zlexer.c?g' \ -e 's?$$(srcdir)/zparser.c?zparser.c?g' \ -e 's?$$(srcdir)/zparser.h?zparser.h?g' \ > $(DEPEND_TMP) cp $(DEPEND_TARGET) $(DEPEND_TMP2) head -`egrep -n "# Dependencies" $(DEPEND_TARGET) | tail -1 | sed -e 's/:.*$$//'` $(DEPEND_TMP2) > $(DEPEND_TARGET) cat $(DEPEND_TMP) >> $(DEPEND_TARGET) @if diff $(DEPEND_TARGET) $(DEPEND_TMP2); then echo " $(DEPEND_TARGET) unchanged"; else echo " Updated $(DEPEND_TARGET))"; fi @if test -f $(DEPEND_TARGET2); then \ cp $(DEPEND_TARGET2) $(DEPEND_TMP2); \ head -`egrep -n "# Dependencies" $(DEPEND_TARGET2) | tail -1 | sed -e 's/:.*$$//'` $(DEPEND_TMP2) > $(DEPEND_TARGET2); \ cat $(DEPEND_TMP) >> $(DEPEND_TARGET2); \ if diff $(DEPEND_TARGET2) $(DEPEND_TMP2); then echo " $(DEPEND_TARGET2) unchanged"; else echo " Updated $(DEPEND_TARGET2))"; fi; \ fi rm -f $(DEPEND_TMP) $(DEPEND_TMP2) # Dependencies answer.o: $(srcdir)/answer.c config.h $(srcdir)/answer.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/tsig.h axfr.o: $(srcdir)/axfr.c config.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/options.h buffer.o: $(srcdir)/buffer.c config.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h configlexer.o: configlexer.c $(srcdir)/configyyrename.h config.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h configparser.h configparser.o: configparser.c config.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/tsig.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/configyyrename.h dbaccess.o: $(srcdir)/dbaccess.c config.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/options.h $(srcdir)/rdata.h $(srcdir)/udb.h \ $(srcdir)/udbradtree.h $(srcdir)/udbzone.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h dbcreate.o: $(srcdir)/dbcreate.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h $(srcdir)/udbradtree.h \ $(srcdir)/udbzone.h $(srcdir)/options.h $(srcdir)/nsd.h $(srcdir)/edns.h difffile.o: $(srcdir)/difffile.c config.h $(srcdir)/difffile.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/udb.h \ $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/udbzone.h $(srcdir)/udbradtree.h $(srcdir)/nsec3.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/tsig.h dname.o: $(srcdir)/dname.c config.h $(srcdir)/dns.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/tsig.h dns.o: $(srcdir)/dns.c config.h $(srcdir)/dns.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h zparser.h edns.o: $(srcdir)/edns.c config.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h \ $(srcdir)/nsd.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h ipc.o: $(srcdir)/ipc.c config.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/region-allocator.h $(srcdir)/buffer.h $(srcdir)/util.h \ $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h \ $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/xfrd-notify.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/packet.h iterated_hash.o: $(srcdir)/iterated_hash.c config.h $(srcdir)/iterated_hash.h lookup3.o: $(srcdir)/lookup3.c config.h $(srcdir)/lookup3.h mini_event.o: $(srcdir)/mini_event.c config.h namedb.o: $(srcdir)/namedb.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsec3.h netio.o: $(srcdir)/netio.c config.h $(srcdir)/netio.h $(srcdir)/region-allocator.h $(srcdir)/util.h nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/remote.h $(srcdir)/xfrd-disk.h nsd-checkconf.o: $(srcdir)/nsd-checkconf.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h nsd-checkzone.o: $(srcdir)/nsd-checkzone.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h nsd-control.o: $(srcdir)/nsd-control.c config.h $(srcdir)/util.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h nsd-mem.o: $(srcdir)/nsd-mem.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/namedb.h \ $(srcdir)/radtree.h $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/udbradtree.h nsec3.o: $(srcdir)/nsec3.c config.h $(srcdir)/nsec3.h $(srcdir)/iterated_hash.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/answer.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/tsig.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/udbradtree.h $(srcdir)/options.h options.o: $(srcdir)/options.c config.h $(srcdir)/options.h $(srcdir)/region-allocator.h $(srcdir)/rbtree.h \ $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/configyyrename.h configparser.h packet.o: $(srcdir)/packet.c config.h $(srcdir)/packet.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/tsig.h \ $(srcdir)/rdata.h query.o: $(srcdir)/query.c config.h $(srcdir)/answer.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/tsig.h $(srcdir)/axfr.h $(srcdir)/options.h $(srcdir)/nsec3.h radtree.o: $(srcdir)/radtree.c config.h $(srcdir)/radtree.h $(srcdir)/util.h $(srcdir)/region-allocator.h rbtree.o: $(srcdir)/rbtree.c config.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h rdata.o: $(srcdir)/rdata.c config.h $(srcdir)/rdata.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h region-allocator.o: $(srcdir)/region-allocator.c config.h $(srcdir)/region-allocator.h $(srcdir)/util.h remote.o: $(srcdir)/remote.c config.h $(srcdir)/remote.h $(srcdir)/util.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h \ $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h \ $(srcdir)/netio.h rrl.o: $(srcdir)/rrl.c config.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h \ $(srcdir)/tsig.h $(srcdir)/lookup3.h $(srcdir)/options.h server.o: $(srcdir)/server.c config.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/netio.h $(srcdir)/xfrd.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h \ $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/nsec3.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/lookup3.h $(srcdir)/rrl.h tsig.o: $(srcdir)/tsig.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h \ $(srcdir)/tsig-openssl.h $(srcdir)/dns.h $(srcdir)/packet.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/nsd.h \ $(srcdir)/edns.h tsig-openssl.o: $(srcdir)/tsig-openssl.c config.h $(srcdir)/tsig-openssl.h $(srcdir)/region-allocator.h \ $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dname.h udb.o: $(srcdir)/udb.c config.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h udbradtree.o: $(srcdir)/udbradtree.c config.h $(srcdir)/udbradtree.h $(srcdir)/udb.h $(srcdir)/radtree.h udbzone.o: $(srcdir)/udbzone.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h \ $(srcdir)/iterated_hash.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/difffile.h $(srcdir)/rbtree.h \ $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/options.h util.o: $(srcdir)/util.c config.h $(srcdir)/util.h $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/zonec.h xfrd.o: $(srcdir)/xfrd.c config.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-tcp.h \ $(srcdir)/xfrd-disk.h $(srcdir)/xfrd-notify.h $(srcdir)/netio.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/rdata.h \ $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/rrl.h $(srcdir)/query.h xfrd-disk.o: $(srcdir)/xfrd-disk.c config.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h xfrd-notify.o: $(srcdir)/xfrd-notify.c config.h $(srcdir)/xfrd-notify.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/rbtree.h $(srcdir)/xfrd.h $(srcdir)/namedb.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/packet.h xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.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)/packet.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h \ $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/options.h zlexer.o: zlexer.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h zparser.h zonec.o: $(srcdir)/zonec.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h zparser.h \ $(srcdir)/options.h $(srcdir)/nsec3.h zparser.o: zparser.c config.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h b64_ntop.o: $(srcdir)/compat/b64_ntop.c config.h b64_pton.o: $(srcdir)/compat/b64_pton.c config.h basename.o: $(srcdir)/compat/basename.c fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(srcdir)/compat/fake-rfc2553.h config.h inet_aton.o: $(srcdir)/compat/inet_aton.c config.h inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h inet_pton.o: $(srcdir)/compat/inet_pton.c config.h malloc.o: $(srcdir)/compat/malloc.c memcmp.o: $(srcdir)/compat/memcmp.c config.h memmove.o: $(srcdir)/compat/memmove.c config.h pselect.o: $(srcdir)/compat/pselect.c config.h reallocarray.o: $(srcdir)/compat/reallocarray.c config.h snprintf.o: $(srcdir)/compat/snprintf.c config.h strlcat.o: $(srcdir)/compat/strlcat.c config.h strlcpy.o: $(srcdir)/compat/strlcpy.c config.h strptime.o: $(srcdir)/compat/strptime.c cutest.o: $(srcdir)/tpkg/cutest/cutest.c config.h $(srcdir)/tpkg/cutest/cutest.h cutest_dname.o: $(srcdir)/tpkg/cutest/cutest_dname.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h cutest_dns.o: $(srcdir)/tpkg/cutest/cutest_dns.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/region-allocator.h $(srcdir)/dns.h cutest_iterated_hash.o: $(srcdir)/tpkg/cutest/cutest_iterated_hash.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/iterated_hash.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h config.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/nsec3.h $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/udbradtree.h $(srcdir)/difffile.h $(srcdir)/namedb.h \ $(srcdir)/options.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h config.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h \ $(srcdir)/edns.h cutest_radtree.o: $(srcdir)/tpkg/cutest/cutest_radtree.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/radtree.h $(srcdir)/region-allocator.h $(srcdir)/util.h cutest_rbtree.o: $(srcdir)/tpkg/cutest/cutest_rbtree.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h cutest_region.o: $(srcdir)/tpkg/cutest/cutest_region.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h cutest_rrl.o: $(srcdir)/tpkg/cutest/cutest_rrl.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/tsig.h cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h \ $(srcdir)/edns.h $(srcdir)/buffer.h cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/udb.h cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/udbradtree.h $(srcdir)/udb.h cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h qtest.o: $(srcdir)/tpkg/cutest/qtest.c config.h $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/namedb.h $(srcdir)/util.h $(srcdir)/nsec3.h \ $(srcdir)/options.h config.h $(srcdir)/packet.h $(srcdir)/dname.h $(srcdir)/rdata.h udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c config.h $(srcdir)/udb.h $(srcdir)/udbradtree.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 nsd-4.1.26/mkinstalldirs0000775000175000017500000000131711024154774014643 0ustar wouterwouter#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs 2739 2008-06-12 08:10:36Z matje $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here nsd-4.1.26/nsd-mem.c0000664000175000017500000002043313345735143013544 0ustar wouterwouter/* * nsd-mem.c -- nsd-mem(8) * * Copyright (c) 2013, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "nsd.h" #include "tsig.h" #include "options.h" #include "namedb.h" #include "udb.h" #include "udbzone.h" #include "util.h" struct nsd nsd; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd-mem [-c configfile]\n"); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } /* zone memory structure */ struct zone_mem { /* size of data (allocated in db.region) */ size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; /* udb data allocated */ size_t udb_data; /* udb overhead (chunk2**x - data) */ size_t udb_overhead; /* count of number of domains */ size_t domaincount; }; /* total memory structure */ struct tot_mem { /* size of data (allocated in db.region) */ size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; /* udb data allocated */ size_t udb_data; /* udb overhead (chunk2**x - data) */ size_t udb_overhead; /* count of number of domains */ size_t domaincount; /* options data */ size_t opt_data; /* unused in options region */ size_t opt_unused; /* dname compression table */ size_t compresstable; #ifdef RATELIMIT /* size of rrl tables */ size_t rrl; #endif /* total ram usage */ size_t ram; /* total nsd.db disk usage */ size_t disk; }; static void account_zone(struct namedb* db, struct zone_mem* zmem) { zmem->data = region_get_mem(db->region); zmem->data_unused = region_get_mem_unused(db->region); if(db->udb) { zmem->udb_data = (size_t)db->udb->alloc->disk->stat_data; zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc - db->udb->alloc->disk->stat_data); } zmem->domaincount = domain_table_count(db->domains); } static void pretty_mem(size_t x, const char* s) { char buf[32]; memset(buf, 0, sizeof(buf)); if(snprintf(buf, sizeof(buf), "%12lld", (long long)x) > 12) { printf("%12lld %s\n", (long long)x, s); return; } printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %s\n", buf[0], buf[1], buf[2], (buf[2]==' '?' ':'.'), buf[3], buf[4], buf[5], (buf[5]==' '?' ':'.'), buf[6], buf[7], buf[8], (buf[8]==' '?' ':'.'), buf[9], buf[10], buf[11], s); } static void print_zone_mem(struct zone_mem* z) { pretty_mem(z->data, "zone data"); pretty_mem(z->data_unused, "zone unused space (due to alignment)"); pretty_mem(z->udb_data, "data in nsd.db"); pretty_mem(z->udb_overhead, "overhead in nsd.db"); } static void account_total(struct nsd_options* opt, struct tot_mem* t) { t->opt_data = region_get_mem(opt->region); t->opt_unused = region_get_mem_unused(opt->region); t->compresstable = sizeof(uint16_t) * (t->domaincount + 1 + EXTRA_DOMAIN_NUMBERS); t->compresstable *= opt->server_count; #ifdef RATELIMIT #define SIZE_RRL_BUCKET (8 + 4 + 4 + 4 + 4 + 2) t->rrl = opt->rrl_size * SIZE_RRL_BUCKET; t->rrl *= opt->server_count; #endif t->ram = t->data + t->data_unused + t->opt_data + t->opt_unused + t->compresstable; #ifdef RATELIMIT t->ram += t->rrl; #endif t->disk = t->udb_data + t->udb_overhead; } static void print_tot_mem(struct tot_mem* t) { printf("\ntotal\n"); pretty_mem(t->data, "data"); pretty_mem(t->data_unused, "unused space (due to alignment)"); pretty_mem(t->opt_data, "options"); pretty_mem(t->opt_unused, "options unused space (due to alignment)"); pretty_mem(t->compresstable, "name table (depends on servercount)"); #ifdef RATELIMIT pretty_mem(t->rrl, "RRL table (depends on servercount)"); #endif pretty_mem(t->udb_data, "data in nsd.db"); pretty_mem(t->udb_overhead, "overhead in nsd.db"); printf("\nsummary\n"); pretty_mem(t->ram, "ram usage (excl space for buffers)"); pretty_mem(t->disk, "disk usage (excl 12% space claimed for growth)"); } static void add_mem(struct tot_mem* t, struct zone_mem* z) { t->data += z->data; t->data_unused += z->data_unused; t->udb_data += z->udb_data; t->udb_overhead += z->udb_overhead; t->domaincount += z->domaincount; } static void check_zone_mem(const char* tf, const char* df, struct zone_options* zo, struct nsd_options* opt, struct tot_mem* totmem) { struct nsd nsd; struct namedb* db; const dname_type* dname = (const dname_type*)zo->node.key; zone_type* zone; struct udb_base* taskudb; udb_ptr last_task; struct zone_mem zmem; printf("zone %s\n", zo->name); /* init*/ memset(&zmem, 0, sizeof(zmem)); memset(&nsd, 0, sizeof(nsd)); nsd.db = db = namedb_open(df, opt); if(!db) error("cannot open %s: %s", df, strerror(errno)); zone = namedb_zone_create(db, dname, zo); taskudb = udb_base_create_new(tf, &namedb_walkfunc, NULL); udb_ptr_init(&last_task, taskudb); /* read the zone */ namedb_read_zonefile(&nsd, zone, taskudb, &last_task); /* account the memory for this zone */ account_zone(db, &zmem); /* pretty print the memory for this zone */ print_zone_mem(&zmem); /* delete the zone from memory */ namedb_close(db); udb_base_free(taskudb); unlink(df); unlink(tf); /* add up totals */ add_mem(totmem, &zmem); } static void check_mem(struct nsd_options* opt) { struct tot_mem totmem; struct zone_options* zo; char tf[512]; char df[512]; memset(&totmem, 0, sizeof(totmem)); snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid()); if(opt->database == NULL || opt->database[0] == 0) df[0] = 0; else snprintf(df, sizeof(df), "./nsd-mem-db-%u.db", (unsigned)getpid()); /* read all zones and account memory */ RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { check_zone_mem(tf, df, zo, opt, &totmem); } /* calculate more total statistics */ account_total(opt, &totmem); /* print statistics */ print_tot_mem(&totmem); /* final advice */ if(opt->database != NULL && opt->database[0] != 0) { printf("\nFinal advice estimate:\n"); printf("(The partial mmap causes reload&AXFR to take longer(disk access))\n"); pretty_mem(totmem.ram + totmem.disk, "data and big mmap"); pretty_mem(totmem.ram + totmem.disk/6, "data and partial mmap"); } } /* dummy functions to link */ struct nsd; int writepid(struct nsd * ATTR_UNUSED(nsd)) { return 0; } void unlinkpid(const char * ATTR_UNUSED(file)) { } void bind8_stats(struct nsd * ATTR_UNUSED(nsd)) { } void sig_handler(int ATTR_UNUSED(sig)) { } extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; struct nsd nsd; const char *configfile = CONFIGFILE; memset(&nsd, 0, sizeof(nsd)); log_init("nsd-mem"); /* Parse the command line... */ while ((c = getopt(argc, argv, "c:h" )) != -1) { switch (c) { case 'c': configfile = optarg; break; case 'h': usage(); exit(0); case '?': default: usage(); exit(1); } } argc -= optind; /* argv += optind; move along argv for positional arguments */ /* Commandline parse error */ if (argc != 0) { usage(); exit(1); } /* Read options */ nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); tsig_init(nsd.options->region); if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { error("could not read zonelist file %s\n", nsd.options->zonelistfile); } if (verbosity == 0) verbosity = nsd.options->verbosity; #ifdef HAVE_CHROOT if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; #ifdef CHROOTDIR /* if still no chrootdir, fallback to default */ if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; #endif /* CHROOTDIR */ #endif /* HAVE_CHROOT */ if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("cannot chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } /* Chroot */ #ifdef HAVE_CHROOT if (nsd.chrootdir && strlen(nsd.chrootdir)) { if(chdir(nsd.chrootdir)) { error("unable to chdir to chroot: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", nsd.chrootdir)); } #endif /* HAVE_CHROOT */ check_mem(nsd.options); exit(0); } nsd-4.1.26/nsd-checkconf.c0000664000175000017500000005565613355422740014725 0ustar wouterwouter/* * checkconf - Read and repeat configuration file to output. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include "tsig.h" #include "options.h" #include "util.h" #include "dname.h" #include "rrl.h" extern char *optarg; extern int optind; static void usage(void) ATTR_NORETURN; #define ZONE_GET_ACL(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote_acl(PATTERN->NAME); \ return; \ } #define ZONE_GET_OUTGOING(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ acl_options_type* acl; \ for(acl=PATTERN->NAME; acl; acl=acl->next) \ quote(acl->ip_address_spec); \ return; \ } #define ZONE_GET_STR(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote(PATTERN->NAME); \ return; \ } #define ZONE_GET_PATH(FINAL, NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quotepath(opt, FINAL, PATTERN->NAME); \ return; \ } #define ZONE_GET_BIN(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%s\n", (PATTERN->NAME)?"yes":"no"); \ return; \ } #define ZONE_GET_RRL(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ zone_print_rrl_whitelist("", PATTERN->NAME); \ return; \ } #define ZONE_GET_INT(NAME, VAR, PATTERN) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%d\n", (int) PATTERN->NAME); \ return; \ } #define SERV_GET_BIN(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%s\n", opt->NAME?"yes":"no"); \ return; \ } #define SERV_GET_STR(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quote(opt->NAME); \ return; \ } #define SERV_GET_PATH(FINAL, NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ quotepath(opt, FINAL, opt->NAME); \ return; \ } #define SERV_GET_INT(NAME, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ printf("%d\n", (int) opt->NAME); \ return; \ } #define SERV_GET_IP(NAME, MEMBER, VAR) \ if (strcasecmp(#NAME, (VAR)) == 0) { \ for(ip = opt->MEMBER; ip; ip=ip->next) \ { \ quote(ip->address); \ } \ return; \ } #ifdef RATELIMIT static void zone_print_rrl_whitelist(const char* s, uint16_t w) { int i; if(w==rrl_type_all) { printf("%sall\n", s); return; } for(i=0x01; i <= 0x80; i<<=1) { if( (w&i) ) printf("%s%s\n", s, rrltype2str(i)); } } #endif /* RATELIMIT */ static char buf[BUFSIZ]; static char * underscore(const char *s) { const char *j = s; size_t i = 0; while(j && *j) { if (*j == '-') { buf[i++] = '_'; } else { buf[i++] = *j; } j++; if (i >= BUFSIZ) { return NULL; } } buf[i] = '\0'; return buf; } static void usage(void) { fprintf(stderr, "usage: nsd-checkconf [-v|-h] [-o option] [-z zonename]\n"); fprintf(stderr, " [-s keyname] \n"); fprintf(stderr, " Checks NSD configuration file for errors.\n"); fprintf(stderr, " Version %s. Report bugs to <%s>.\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); fprintf(stderr, "Use with a configfile as argument to check syntax.\n"); fprintf(stderr, "Use with -o, -z or -s options to query the configuration.\n\n"); fprintf(stderr, "-v Verbose, echo settings that take effect to std output.\n"); fprintf(stderr, "-h Print this help information.\n"); fprintf(stderr, "-f Use with -o to print final pathnames, ie. with chroot.\n"); fprintf(stderr, "-o option Print value of the option specified to stdout.\n"); fprintf(stderr, "-p pattern Print option value for the pattern given.\n"); fprintf(stderr, "-z zonename Print option value for the zone given.\n"); fprintf(stderr, "-a keyname Print algorithm name for the TSIG key.\n"); fprintf(stderr, "-s keyname Print base64 secret blob for the TSIG key.\n"); exit(1); } static void print_string_var(const char* varname, const char* value) { if (!value) { printf("\t#%s\n", varname); } else { printf("\t%s \"%s\"\n", varname, value); } } static void quote(const char *v) { if(v==NULL) printf("\n"); else printf("%s\n", v); } static void quotepath(nsd_options_type* opt, int final, const char *f) { const char* chr = opt->chroot; #ifdef CHROOTDIR if(chr == 0) chr = CHROOTDIR; #endif if(f == 0 || f[0] == '/' || !final || !chr || chr[0]==0) { quote(f); return; } /* chroot has had trailing slash applied in check part of checkconf */ printf("%s%s\n", chr, f); } static void quote_acl(acl_options_type* acl) { while(acl) { printf("%s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)"))); acl=acl->next; } } static void print_acl(const char* varname, acl_options_type* acl) { while(acl) { printf("\t%s ", varname); if(acl->use_axfr_only) printf("AXFR "); if(acl->allow_udp) printf("UDP "); printf("%s %s\n", acl->ip_address_spec, acl->nokey?"NOKEY":(acl->blocked?"BLOCKED": (acl->key_name?acl->key_name:"(null)"))); if(verbosity>1) { printf("\t# %s", acl->is_ipv6?"ip6":"ip4"); if(acl->port == 0) printf(" noport"); else printf(" port=%d", acl->port); if(acl->rangetype == acl_range_single) printf(" single"); if(acl->rangetype == acl_range_mask) printf(" masked"); if(acl->rangetype == acl_range_subnet) printf(" subnet"); if(acl->rangetype == acl_range_minmax) printf(" minmax"); if(acl->is_ipv6) { #ifdef INET6 char dest[128]; inet_ntop(AF_INET6, &acl->addr.addr6, dest, sizeof(dest)); printf(" addr=%s", dest); if(acl->rangetype != acl_range_single) { inet_ntop(AF_INET6, &acl->range_mask.addr6, dest, sizeof(dest)); printf(" rangemask=%s", dest); } #else printf(" ip6addr-noip6defined"); #endif } else { char dest[128]; inet_ntop(AF_INET, &acl->addr.addr, dest, sizeof(dest)); printf(" addr=%s", dest); if(acl->rangetype != acl_range_single) { inet_ntop(AF_INET, &acl->range_mask.addr, dest, sizeof(dest)); printf(" rangemask=%s", dest); } } printf("\n"); } acl=acl->next; } } static void print_acl_ips(const char* varname, acl_options_type* acl) { while(acl) { printf("\t%s %s\n", varname, acl->ip_address_spec); acl=acl->next; } } void config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, const char *z, const char* pat, int final) { ip_address_option_type* ip; if (k) { /* find key */ key_options_type* key = key_options_find(opt, k); if(key) { if (s) { quote(key->secret); } else { quote(key->algorithm); } return; } printf("Could not find key %s\n", k); return; } if (!o) { return; } if (z) { zone_options_type* zone; const dname_type *dname = dname_parse(opt->region, z); if(!dname) { printf("Could not parse zone name %s\n", z); exit(1); } zone = zone_options_find(opt, dname); if(!zone) { printf("Zone does not exist: %s\n", z); exit(1); } ZONE_GET_STR(name, o, zone); if(strcasecmp("pattern", o)==0) { quote(zone->pattern->pname); return; } ZONE_GET_BIN(part_of_config, o, zone); ZONE_GET_PATH(final, zonefile, o, zone->pattern); ZONE_GET_ACL(request_xfr, o, zone->pattern); ZONE_GET_ACL(provide_xfr, o, zone->pattern); ZONE_GET_ACL(allow_notify, o, zone->pattern); ZONE_GET_ACL(notify, o, zone->pattern); ZONE_GET_BIN(notify_retry, o, zone->pattern); ZONE_GET_STR(zonestats, o, zone->pattern); ZONE_GET_OUTGOING(outgoing_interface, o, zone->pattern); ZONE_GET_BIN(allow_axfr_fallback, o, zone->pattern); ZONE_GET_INT(max_refresh_time, o, zone->pattern); ZONE_GET_INT(min_refresh_time, o, zone->pattern); ZONE_GET_INT(max_retry_time, o, zone->pattern); ZONE_GET_INT(min_retry_time, o, zone->pattern); ZONE_GET_INT(size_limit_xfr, o, zone->pattern); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, zone->pattern); #endif ZONE_GET_BIN(multi_master_check, o, zone->pattern); printf("Zone option not handled: %s %s\n", z, o); exit(1); } else if(pat) { pattern_options_type* p = pattern_options_find(opt, pat); if(!p) { printf("Pattern does not exist: %s\n", pat); exit(1); } if(strcasecmp("name", o)==0) { quote(p->pname); return; } ZONE_GET_STR(zonefile, o, p); ZONE_GET_PATH(final, zonefile, o, p); ZONE_GET_ACL(request_xfr, o, p); ZONE_GET_ACL(provide_xfr, o, p); ZONE_GET_ACL(allow_notify, o, p); ZONE_GET_ACL(notify, o, p); ZONE_GET_BIN(notify_retry, o, p); ZONE_GET_STR(zonestats, o, p); ZONE_GET_OUTGOING(outgoing_interface, o, p); ZONE_GET_BIN(allow_axfr_fallback, o, p); ZONE_GET_INT(max_refresh_time, o, p); ZONE_GET_INT(min_refresh_time, o, p); ZONE_GET_INT(max_retry_time, o, p); ZONE_GET_INT(min_retry_time, o, p); ZONE_GET_INT(size_limit_xfr, o, p); #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, p); #endif ZONE_GET_BIN(multi_master_check, o, p); printf("Pattern option not handled: %s %s\n", pat, o); exit(1); } else { /* look in the server section */ SERV_GET_IP(ip_address, ip_addresses, o); /* bin */ SERV_GET_BIN(ip_transparent, o); SERV_GET_BIN(ip_freebind, o); SERV_GET_BIN(debug_mode, o); SERV_GET_BIN(do_ip4, o); SERV_GET_BIN(do_ip6, o); SERV_GET_BIN(reuseport, o); SERV_GET_BIN(hide_version, o); SERV_GET_BIN(zonefiles_check, o); SERV_GET_BIN(log_time_ascii, o); SERV_GET_BIN(round_robin, o); SERV_GET_BIN(minimal_responses, o); SERV_GET_BIN(refuse_any, o); /* str */ SERV_GET_PATH(final, database, o); SERV_GET_STR(identity, o); SERV_GET_STR(version, o); SERV_GET_STR(nsid, o); SERV_GET_PATH(final, logfile, o); SERV_GET_PATH(final, pidfile, o); SERV_GET_STR(chroot, o); SERV_GET_STR(username, o); SERV_GET_PATH(final, zonesdir, o); SERV_GET_PATH(final, xfrdfile, o); SERV_GET_PATH(final, xfrdir, o); SERV_GET_PATH(final, zonelistfile, o); SERV_GET_STR(port, o); /* int */ SERV_GET_INT(server_count, o); SERV_GET_INT(tcp_count, o); SERV_GET_INT(tcp_query_count, o); SERV_GET_INT(tcp_timeout, o); SERV_GET_INT(tcp_mss, o); SERV_GET_INT(outgoing_tcp_mss, o); SERV_GET_INT(ipv4_edns_size, o); SERV_GET_INT(ipv6_edns_size, o); SERV_GET_INT(statistics, o); SERV_GET_INT(xfrd_reload_timeout, o); SERV_GET_INT(verbosity, o); #ifdef RATELIMIT SERV_GET_INT(rrl_size, o); SERV_GET_INT(rrl_ratelimit, o); SERV_GET_INT(rrl_slip, o); SERV_GET_INT(rrl_ipv4_prefix_length, o); SERV_GET_INT(rrl_ipv6_prefix_length, o); SERV_GET_INT(rrl_whitelist_ratelimit, o); #endif #ifdef USE_DNSTAP SERV_GET_BIN(dnstap_enable, o); SERV_GET_STR(dnstap_socket_path, o); SERV_GET_BIN(dnstap_send_identity, o); SERV_GET_BIN(dnstap_send_version, o); SERV_GET_STR(dnstap_identity, o); SERV_GET_STR(dnstap_version, o); SERV_GET_BIN(dnstap_log_auth_query_messages, o); SERV_GET_BIN(dnstap_log_auth_response_messages, o); #endif SERV_GET_INT(zonefiles_write, o); /* remote control */ SERV_GET_BIN(control_enable, o); SERV_GET_IP(control_interface, control_interface, o); SERV_GET_INT(control_port, o); SERV_GET_STR(server_key_file, o); SERV_GET_STR(server_cert_file, o); SERV_GET_STR(control_key_file, o); SERV_GET_STR(control_cert_file, o); if(strcasecmp(o, "zones") == 0) { zone_options_type* zone; RBTREE_FOR(zone, zone_options_type*, opt->zone_options) quote(zone->name); return; } if(strcasecmp(o, "patterns") == 0) { pattern_options_type* p; RBTREE_FOR(p, pattern_options_type*, opt->patterns) quote(p->pname); return; } printf("Server option not handled: %s\n", o); exit(1); } } /* print zone content items */ static void print_zone_content_elems(pattern_options_type* pat) { if(pat->zonefile) print_string_var("zonefile:", pat->zonefile); #ifdef RATELIMIT zone_print_rrl_whitelist("\trrl-whitelist: ", pat->rrl_whitelist); #endif print_acl("allow-notify:", pat->allow_notify); print_acl("request-xfr:", pat->request_xfr); if(pat->multi_master_check) printf("\tmulti-master-check: %s\n", pat->multi_master_check?"yes":"no"); if(!pat->notify_retry_is_default) printf("\tnotify-retry: %d\n", pat->notify_retry); print_acl("notify:", pat->notify); print_acl("provide-xfr:", pat->provide_xfr); if(pat->zonestats) print_string_var("zonestats:", pat->zonestats); print_acl_ips("outgoing-interface:", pat->outgoing_interface); if(!pat->allow_axfr_fallback_is_default) printf("\tallow-axfr-fallback: %s\n", pat->allow_axfr_fallback?"yes":"no"); if(!pat->max_refresh_time_is_default) printf("\tmax-refresh-time: %d\n", pat->max_refresh_time); if(!pat->min_refresh_time_is_default) printf("\tmin-refresh-time: %d\n", pat->min_refresh_time); if(!pat->max_retry_time_is_default) printf("\tmax-retry-time: %d\n", pat->max_retry_time); if(!pat->min_retry_time_is_default) printf("\tmin-retry-time: %d\n", pat->min_retry_time); if(pat->size_limit_xfr != 0) printf("\tsize-limit-xfr: %llu\n", (long long unsigned)pat->size_limit_xfr); } void config_test_print_server(nsd_options_type* opt) { ip_address_option_type* ip; key_options_type* key; zone_options_type* zone; pattern_options_type* pat; printf("# Config settings.\n"); printf("server:\n"); printf("\tdebug-mode: %s\n", opt->debug_mode?"yes":"no"); printf("\tip-transparent: %s\n", opt->ip_transparent?"yes":"no"); printf("\tip-freebind: %s\n", opt->ip_freebind?"yes":"no"); printf("\treuseport: %s\n", opt->reuseport?"yes":"no"); printf("\tdo-ip4: %s\n", opt->do_ip4?"yes":"no"); printf("\tdo-ip6: %s\n", opt->do_ip6?"yes":"no"); printf("\thide-version: %s\n", opt->hide_version?"yes":"no"); print_string_var("database:", opt->database); print_string_var("identity:", opt->identity); print_string_var("version:", opt->version); print_string_var("nsid:", opt->nsid); print_string_var("logfile:", opt->logfile); printf("\tserver-count: %d\n", opt->server_count); printf("\ttcp-count: %d\n", opt->tcp_count); printf("\ttcp-query-count: %d\n", opt->tcp_query_count); printf("\ttcp-timeout: %d\n", opt->tcp_timeout); printf("\ttcp-mss: %d\n", opt->tcp_mss); printf("\toutgoing-tcp-mss: %d\n", opt->outgoing_tcp_mss); printf("\tipv4-edns-size: %d\n", (int) opt->ipv4_edns_size); printf("\tipv6-edns-size: %d\n", (int) opt->ipv6_edns_size); print_string_var("pidfile:", opt->pidfile); print_string_var("port:", opt->port); printf("\tstatistics: %d\n", opt->statistics); print_string_var("chroot:", opt->chroot); print_string_var("username:", opt->username); print_string_var("zonesdir:", opt->zonesdir); print_string_var("xfrdfile:", opt->xfrdfile); print_string_var("zonelistfile:", opt->zonelistfile); print_string_var("xfrdir:", opt->xfrdir); printf("\txfrd-reload-timeout: %d\n", opt->xfrd_reload_timeout); printf("\tlog-time-ascii: %s\n", opt->log_time_ascii?"yes":"no"); printf("\tround-robin: %s\n", opt->round_robin?"yes":"no"); printf("\tminimal-responses: %s\n", opt->minimal_responses?"yes":"no"); printf("\trefuse-any: %s\n", opt->refuse_any?"yes":"no"); printf("\tverbosity: %d\n", opt->verbosity); for(ip = opt->ip_addresses; ip; ip=ip->next) { print_string_var("ip-address:", ip->address); } #ifdef RATELIMIT printf("\trrl-size: %d\n", (int)opt->rrl_size); printf("\trrl-ratelimit: %d\n", (int)opt->rrl_ratelimit); printf("\trrl-slip: %d\n", (int)opt->rrl_slip); printf("\trrl-ipv4-prefix-length: %d\n", (int)opt->rrl_ipv4_prefix_length); printf("\trrl-ipv6-prefix-length: %d\n", (int)opt->rrl_ipv6_prefix_length); printf("\trrl-whitelist-ratelimit: %d\n", (int)opt->rrl_whitelist_ratelimit); #endif printf("\tzonefiles-check: %s\n", opt->zonefiles_check?"yes":"no"); printf("\tzonefiles-write: %d\n", opt->zonefiles_write); #ifdef USE_DNSTAP printf("\ndnstap:\n"); printf("\tdnstap-enable: %s\n", opt->dnstap_enable?"yes":"no"); print_string_var("dnstap-socket-path:", opt->dnstap_socket_path); printf("\tdnstap-send-identity: %s\n", opt->dnstap_send_identity?"yes":"no"); printf("\tdnstap-send-version: %s\n", opt->dnstap_send_version?"yes":"no"); print_string_var("dnstap-identity:", opt->dnstap_identity); print_string_var("dnstap-version:", opt->dnstap_version); printf("\tdnstap-log-auth-query-messages: %s\n", opt->dnstap_log_auth_query_messages?"yes":"no"); printf("\tdnstap-log-auth-response-messages: %s\n", opt->dnstap_log_auth_response_messages?"yes":"no"); #endif printf("\nremote-control:\n"); printf("\tcontrol-enable: %s\n", opt->control_enable?"yes":"no"); for(ip = opt->control_interface; ip; ip=ip->next) print_string_var("control-interface:", ip->address); printf("\tcontrol-port: %d\n", opt->control_port); print_string_var("server-key-file:", opt->server_key_file); print_string_var("server-cert-file:", opt->server_cert_file); print_string_var("control-key-file:", opt->control_key_file); print_string_var("control-cert-file:", opt->control_cert_file); RBTREE_FOR(key, key_options_type*, opt->keys) { printf("\nkey:\n"); print_string_var("name:", key->name); print_string_var("algorithm:", key->algorithm); print_string_var("secret:", key->secret); } RBTREE_FOR(pat, pattern_options_type*, opt->patterns) { if(pat->implicit) continue; printf("\npattern:\n"); print_string_var("name:", pat->pname); print_zone_content_elems(pat); } RBTREE_FOR(zone, zone_options_type*, opt->zone_options) { if(!zone->part_of_config) continue; printf("\nzone:\n"); print_string_var("name:", zone->name); print_zone_content_elems(zone->pattern); } } static int additional_checks(nsd_options_type* opt, const char* filename) { zone_options_type* zone; int errors = 0; RBTREE_FOR(zone, zone_options_type*, opt->zone_options) { const dname_type* dname = dname_parse(opt->region, zone->name); /* memory leak. */ if(!dname) { fprintf(stderr, "%s: cannot parse zone name syntax for zone %s.\n", filename, zone->name); errors ++; continue; } #ifndef ROOT_SERVER /* Is it a root zone? Are we a root server then? Idiot proof. */ if(dname->label_count == 1) { fprintf(stderr, "%s: not configured as a root server.\n", filename); errors ++; } #endif if(zone->pattern->allow_notify && !zone->pattern->request_xfr) { fprintf(stderr, "%s: zone %s has allow-notify but no request-xfr" " items. Where can it get a zone transfer when a notify " "is received?\n", filename, zone->name); errors ++; } if(!zone_is_slave(zone) && (!zone->pattern->zonefile || zone->pattern->zonefile[0] == 0)) { fprintf(stderr, "%s: zone %s is a master zone but has " "no zonefile. Where can the data come from?\n", filename, zone->name); errors ++; } } #ifndef BIND8_STATS if(opt->statistics > 0) { fprintf(stderr, "%s: 'statistics: %d' but BIND 8 statistics feature not enabled.\n", filename, opt->statistics); errors ++; } #endif #ifndef HAVE_CHROOT if(opt->chroot != 0) { fprintf(stderr, "%s: chroot %s given. chroot not supported on this platform.\n", filename, opt->chroot); errors ++; } #endif if (opt->identity && strlen(opt->identity) > UCHAR_MAX) { fprintf(stderr, "%s: server identity too long (%u characters)\n", filename, (unsigned) strlen(opt->identity)); errors ++; } if (opt->version && strlen(opt->version) > UCHAR_MAX) { fprintf(stderr, "%s: server version too long (%u characters)\n", filename, (unsigned) strlen(opt->version)); errors ++; } /* not done here: parsing of ip-address. parsing of username. */ if (opt->chroot && opt->chroot[0]) { /* append trailing slash for strncmp checking */ append_trailing_slash(&opt->chroot, opt->region); append_trailing_slash(&opt->xfrdir, opt->region); append_trailing_slash(&opt->zonesdir, opt->region); /* zonesdir must be absolute and within chroot, * all other pathnames may be relative to zonesdir */ if (strncmp(opt->zonesdir, opt->chroot, strlen(opt->chroot)) != 0) { fprintf(stderr, "%s: zonesdir %s has to be an absolute path that starts with the chroot path %s\n", filename, opt->zonesdir, opt->chroot); errors ++; } if (!file_inside_chroot(opt->pidfile, opt->chroot)) { fprintf(stderr, "%s: pidfile %s is not relative to chroot %s.\n", filename, opt->pidfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->database, opt->chroot)) { fprintf(stderr, "%s: database %s is not relative to chroot %s.\n", filename, opt->database, opt->chroot); errors ++; } if (!file_inside_chroot(opt->xfrdfile, opt->chroot)) { fprintf(stderr, "%s: xfrdfile %s is not relative to chroot %s.\n", filename, opt->xfrdfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->zonelistfile, opt->chroot)) { fprintf(stderr, "%s: zonelistfile %s is not relative to chroot %s.\n", filename, opt->zonelistfile, opt->chroot); errors ++; } if (!file_inside_chroot(opt->xfrdir, opt->chroot)) { fprintf(stderr, "%s: xfrdir %s is not relative to chroot %s.\n", filename, opt->xfrdir, opt->chroot); errors ++; } } if (atoi(opt->port) <= 0) { fprintf(stderr, "%s: port number '%s' is not a positive number.\n", filename, opt->port); errors ++; } if(errors != 0) { fprintf(stderr, "%s: %d semantic errors in %d zones, %d keys.\n", filename, errors, (int)nsd_options_num_zones(opt), (int)opt->keys->count); } return (errors == 0); } int main(int argc, char* argv[]) { int c; int verbose = 0; int key_sec = 0; int final = 0; const char * conf_opt = NULL; /* what option do you want? Can be NULL -> print all */ const char * conf_zone = NULL; /* what zone are we talking about */ const char * conf_key = NULL; /* what key is needed */ const char * conf_pat = NULL; /* what pattern is talked about */ const char* configfile; nsd_options_type *options; log_init("nsd-checkconf"); /* Parse the command line... */ while ((c = getopt(argc, argv, "vfo:a:p:s:z:")) != -1) { switch (c) { case 'v': verbose = 1; verbosity++; break; case 'o': conf_opt = optarg; break; case 'f': final = 1; break; case 'p': conf_pat = optarg; break; case 'a': if (conf_key) { fprintf(stderr, "Error: cannot combine -a with -s or other -a.\n"); exit(1); } conf_key = optarg; break; case 's': if (conf_key) { fprintf(stderr, "Error: cannot combine -s with -a or other -s.\n"); exit(1); } conf_key = optarg; key_sec = 1; break; case 'z': conf_zone = optarg; break; default: usage(); }; } argc -= optind; argv += optind; if (argc == 0 || argc>=2) { usage(); } configfile = argv[0]; /* read config file */ options = nsd_options_create(region_create(xalloc, free)); tsig_init(options->region); if (!parse_options_file(options, configfile, NULL, NULL) || !additional_checks(options, configfile)) { exit(2); } if (conf_opt || conf_key) { config_print_zone(options, conf_key, key_sec, underscore(conf_opt), conf_zone, conf_pat, final); } else { if (verbose) { printf("# Read file %s: %d patterns, %d fixed-zones, " "%d keys.\n", configfile, (int)options->patterns->count, (int)nsd_options_num_zones(options), (int)options->keys->count); config_test_print_server(options); } } return 0; } nsd-4.1.26/dns.h0000664000175000017500000002401413317655232012773 0ustar wouterwouter/* * dns.h -- DNS definitions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _DNS_H_ #define _DNS_H_ enum rr_section { QUESTION_SECTION, ANSWER_SECTION, AUTHORITY_SECTION, /* * Use a split authority section to ensure that optional * NS RRsets in the response can be omitted. */ OPTIONAL_AUTHORITY_SECTION, ADDITIONAL_SECTION, /* * Use a split additional section to ensure A records appear * before any AAAA records (this is recommended practice to * avoid truncating the additional section for IPv4 clients * that do not specify EDNS0), and AAAA records before other * types of additional records (such as X25 and ISDN). * Encode_answer sets the ARCOUNT field of the response packet * correctly. */ ADDITIONAL_A_SECTION = ADDITIONAL_SECTION, ADDITIONAL_AAAA_SECTION, ADDITIONAL_OTHER_SECTION, RR_SECTION_COUNT }; typedef enum rr_section rr_section_type; /* Possible OPCODE values */ #define OPCODE_QUERY 0 /* a standard query (QUERY) */ #define OPCODE_IQUERY 1 /* an inverse query (IQUERY) */ #define OPCODE_STATUS 2 /* a server status request (STATUS) */ #define OPCODE_NOTIFY 4 /* NOTIFY */ #define OPCODE_UPDATE 5 /* Dynamic update */ /* Possible RCODE values */ #define RCODE_OK 0 /* No error condition */ #define RCODE_FORMAT 1 /* Format error */ #define RCODE_SERVFAIL 2 /* Server failure */ #define RCODE_NXDOMAIN 3 /* Name Error */ #define RCODE_IMPL 4 /* Not implemented */ #define RCODE_REFUSE 5 /* Refused */ #define RCODE_YXDOMAIN 6 /* name should not exist */ #define RCODE_YXRRSET 7 /* rrset should not exist */ #define RCODE_NXRRSET 8 /* rrset does not exist */ #define RCODE_NOTAUTH 9 /* server not authoritative */ #define RCODE_NOTZONE 10 /* name not inside zone */ /* Standardized NSD return code. Partially maps to DNS RCODE values. */ enum nsd_rc { /* Discard the client request. */ NSD_RC_DISCARD = -1, /* OK, continue normal processing. */ NSD_RC_OK = RCODE_OK, /* Return the appropriate error code to the client. */ NSD_RC_FORMAT = RCODE_FORMAT, NSD_RC_SERVFAIL = RCODE_SERVFAIL, NSD_RC_NXDOMAIN = RCODE_NXDOMAIN, NSD_RC_IMPL = RCODE_IMPL, NSD_RC_REFUSE = RCODE_REFUSE, NSD_RC_NOTAUTH = RCODE_NOTAUTH }; typedef enum nsd_rc nsd_rc_type; /* RFC1035 */ #define CLASS_IN 1 /* Class IN */ #define CLASS_CS 2 /* Class CS */ #define CLASS_CH 3 /* Class CHAOS */ #define CLASS_HS 4 /* Class HS */ #define CLASS_NONE 254 /* Class NONE rfc2136 */ #define CLASS_ANY 255 /* Class ANY */ #define TYPE_A 1 /* a host address */ #define TYPE_NS 2 /* an authoritative name server */ #define TYPE_MD 3 /* a mail destination (Obsolete - use MX) */ #define TYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ #define TYPE_CNAME 5 /* the canonical name for an alias */ #define TYPE_SOA 6 /* marks the start of a zone of authority */ #define TYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ #define TYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ #define TYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ #define TYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ #define TYPE_WKS 11 /* a well known service description */ #define TYPE_PTR 12 /* a domain name pointer */ #define TYPE_HINFO 13 /* host information */ #define TYPE_MINFO 14 /* mailbox or mail list information */ #define TYPE_MX 15 /* mail exchange */ #define TYPE_TXT 16 /* text strings */ #define TYPE_RP 17 /* RFC1183 */ #define TYPE_AFSDB 18 /* RFC1183 */ #define TYPE_X25 19 /* RFC1183 */ #define TYPE_ISDN 20 /* RFC1183 */ #define TYPE_RT 21 /* RFC1183 */ #define TYPE_NSAP 22 /* RFC1706 */ #define TYPE_SIG 24 /* 2535typecode */ #define TYPE_KEY 25 /* 2535typecode */ #define TYPE_PX 26 /* RFC2163 */ #define TYPE_AAAA 28 /* ipv6 address */ #define TYPE_LOC 29 /* LOC record RFC1876 */ #define TYPE_NXT 30 /* 2535typecode */ #define TYPE_SRV 33 /* SRV record RFC2782 */ #define TYPE_NAPTR 35 /* RFC2915 */ #define TYPE_KX 36 /* RFC2230 Key Exchange Delegation Record */ #define TYPE_CERT 37 /* RFC2538 */ #define TYPE_A6 38 /* RFC2874 */ #define TYPE_DNAME 39 /* RFC2672 */ #define TYPE_OPT 41 /* Pseudo OPT record... */ #define TYPE_APL 42 /* RFC3123 */ #define TYPE_DS 43 /* RFC 4033, 4034, and 4035 */ #define TYPE_SSHFP 44 /* SSH Key Fingerprint */ #define TYPE_IPSECKEY 45 /* public key for ipsec use. RFC 4025 */ #define TYPE_RRSIG 46 /* RFC 4033, 4034, and 4035 */ #define TYPE_NSEC 47 /* RFC 4033, 4034, and 4035 */ #define TYPE_DNSKEY 48 /* RFC 4033, 4034, and 4035 */ #define TYPE_DHCID 49 /* RFC4701 DHCP information */ #define TYPE_NSEC3 50 /* NSEC3, secure denial, prevents zonewalking */ #define TYPE_NSEC3PARAM 51 /* NSEC3PARAM at zone apex nsec3 parameters */ #define TYPE_TLSA 52 /* RFC 6698 */ #define TYPE_SMIMEA 53 /* RFC 8162 */ #define TYPE_CDS 59 /* RFC 7344 */ #define TYPE_CDNSKEY 60 /* RFC 7344 */ #define TYPE_OPENPGPKEY 61 /* RFC 7929 */ #define TYPE_CSYNC 62 /* RFC 7477 */ #define TYPE_SPF 99 /* RFC 4408 */ #define TYPE_NID 104 /* RFC 6742 */ #define TYPE_L32 105 /* RFC 6742 */ #define TYPE_L64 106 /* RFC 6742 */ #define TYPE_LP 107 /* RFC 6742 */ #define TYPE_EUI48 108 /* RFC 7043 */ #define TYPE_EUI64 109 /* RFC 7043 */ #define TYPE_TSIG 250 #define TYPE_IXFR 251 #define TYPE_AXFR 252 #define TYPE_MAILB 253 /* A request for mailbox-related records (MB, MG or MR) */ #define TYPE_MAILA 254 /* A request for mail agent RRs (Obsolete - see MX) */ #define TYPE_ANY 255 /* any type (wildcard) */ #define TYPE_URI 256 /* RFC 7553 */ #define TYPE_CAA 257 /* RFC 6844 */ #define TYPE_AVC 258 #define TYPE_DLV 32769 /* RFC 4431 */ #define PSEUDO_TYPE_DLV RRTYPE_DESCRIPTORS_LENGTH #define MAXLABELLEN 63 #define MAXDOMAINLEN 255 #define MAXRDATALEN 64 /* This is more than enough, think multiple TXT. */ #define MAX_RDLENGTH 65535 /* Maximum size of a single RR. */ #define MAX_RR_SIZE \ (MAXDOMAINLEN + sizeof(uint32_t) + 4*sizeof(uint16_t) + MAX_RDLENGTH) #define IP4ADDRLEN (32/8) #define IP6ADDRLEN (128/8) #define EUI48ADDRLEN (48/8) #define EUI64ADDRLEN (64/8) #define NSEC3_HASH_LEN 20 /* * The different types of RDATA wireformat data. */ enum rdata_wireformat { RDATA_WF_COMPRESSED_DNAME, /* Possibly compressed domain name. */ RDATA_WF_UNCOMPRESSED_DNAME, /* Uncompressed domain name. */ RDATA_WF_LITERAL_DNAME, /* Literal (not downcased) dname. */ RDATA_WF_BYTE, /* 8-bit integer. */ RDATA_WF_SHORT, /* 16-bit integer. */ RDATA_WF_LONG, /* 32-bit integer. */ RDATA_WF_TEXT, /* Text string. */ RDATA_WF_TEXTS, /* Text string sequence. */ RDATA_WF_A, /* 32-bit IPv4 address. */ RDATA_WF_AAAA, /* 128-bit IPv6 address. */ RDATA_WF_BINARY, /* Binary data (unknown length). */ RDATA_WF_BINARYWITHLENGTH, /* Binary data preceded by 1 byte length */ RDATA_WF_APL, /* APL data. */ RDATA_WF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */ RDATA_WF_ILNP64, /* 64-bit uncompressed IPv6 address. */ RDATA_WF_EUI48, /* 48-bit address. */ RDATA_WF_EUI64, /* 64-bit address. */ RDATA_WF_LONG_TEXT /* Long (>255) text string. */ }; typedef enum rdata_wireformat rdata_wireformat_type; /* * The different types of RDATA that can appear in the zone file. */ enum rdata_zoneformat { RDATA_ZF_DNAME, /* Domain name. */ RDATA_ZF_LITERAL_DNAME, /* DNS name (not lowercased domain name). */ RDATA_ZF_TEXT, /* Text string. */ RDATA_ZF_TEXTS, /* Text string sequence. */ RDATA_ZF_BYTE, /* 8-bit integer. */ RDATA_ZF_SHORT, /* 16-bit integer. */ RDATA_ZF_LONG, /* 32-bit integer. */ RDATA_ZF_A, /* 32-bit IPv4 address. */ RDATA_ZF_AAAA, /* 128-bit IPv6 address. */ RDATA_ZF_RRTYPE, /* RR type. */ RDATA_ZF_ALGORITHM, /* Cryptographic algorithm. */ RDATA_ZF_CERTIFICATE_TYPE, RDATA_ZF_PERIOD, /* Time period. */ RDATA_ZF_TIME, RDATA_ZF_BASE64, /* Base-64 binary data. */ RDATA_ZF_BASE32, /* Base-32 binary data. */ RDATA_ZF_HEX, /* Hexadecimal binary data. */ RDATA_ZF_HEX_LEN, /* Hexadecimal binary data. Skip initial length byte. */ RDATA_ZF_NSAP, /* NSAP. */ RDATA_ZF_APL, /* APL. */ RDATA_ZF_IPSECGATEWAY, /* IPSECKEY gateway ip4, ip6 or dname. */ RDATA_ZF_SERVICES, /* Protocol and port number bitmap. */ RDATA_ZF_NXT, /* NXT type bitmap. */ RDATA_ZF_NSEC, /* NSEC type bitmap. */ RDATA_ZF_LOC, /* Location data. */ RDATA_ZF_ILNP64, /* 64-bit uncompressed IPv6 address. */ RDATA_ZF_EUI48, /* EUI48 address. */ RDATA_ZF_EUI64, /* EUI64 address. */ RDATA_ZF_LONG_TEXT, /* Long (>255) text string. */ RDATA_ZF_TAG, /* Text string without quotes. */ RDATA_ZF_UNKNOWN /* Unknown data. */ }; typedef enum rdata_zoneformat rdata_zoneformat_type; struct rrtype_descriptor { uint16_t type; /* RR type */ const char *name; /* Textual name. */ int token; /* Parser token. */ uint32_t minimum; /* Minimum number of RDATAs. */ uint32_t maximum; /* Maximum number of RDATAs. */ uint8_t wireformat[MAXRDATALEN]; /* rdata_wireformat_type */ uint8_t zoneformat[MAXRDATALEN]; /* rdata_zoneformat_type */ }; typedef struct rrtype_descriptor rrtype_descriptor_type; /* * Indexed by type. The special type "0" can be used to get a * descriptor for unknown types (with one binary rdata). * * AVC + 1 */ #define RRTYPE_DESCRIPTORS_LENGTH (TYPE_AVC + 1) rrtype_descriptor_type *rrtype_descriptor_by_name(const char *name); rrtype_descriptor_type *rrtype_descriptor_by_type(uint16_t type); const char *rrtype_to_string(uint16_t rrtype); /* * Lookup the type in the ztypes lookup table. If not found, check if * the type uses the "TYPExxx" notation for unknown types. * * Return 0 if no type matches. */ uint16_t rrtype_from_string(const char *name); const char *rrclass_to_string(uint16_t rrclass); uint16_t rrclass_from_string(const char *name); #ifdef __cplusplus inline rr_section_type operator++(rr_section_type &lhs) { lhs = (rr_section_type) ((int) lhs + 1); return lhs; } #endif /* __cplusplus */ #endif /* _DNS_H_ */ nsd-4.1.26/xfr-inspect.c0000664000175000017500000002766313243032013014441 0ustar wouterwouter/* xfr-inspect - list the contents and inspect an zone transfer XFR file * By W.C.A. Wijngaards * Copyright 2017, NLnet Labs. * BSD, see LICENSE. */ #include "config.h" #include "udbzone.h" #include "util.h" #include "buffer.h" #include "packet.h" #include "rdata.h" #include "namedb.h" #include "difffile.h" #include #include #include #include #include #include /** verbosity for inspect */ static int v = 0; /** shorthand for ease */ #ifdef ULL #undef ULL #endif #define ULL (unsigned long long) /** print usage text */ static void usage(void) { printf("usage: xfr-inspect [options] file\n"); printf(" -h this help\n"); printf(" -v increase verbosity: " "with -v(list chunks), -vv(inside chunks)\n"); printf(" -l list contents of transfer\n"); } static int xi_diff_read_64(FILE *in, uint64_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } static int xi_diff_read_32(FILE *in, uint32_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { *result = ntohl(*result); return 1; } else { return 0; } } static int xi_diff_read_8(FILE *in, uint8_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } static int xi_diff_read_str(FILE* in, char* buf, size_t len) { uint32_t disklen; if(!xi_diff_read_32(in, &disklen)) return 0; if(disklen >= len) return 0; if(fread(buf, disklen, 1, in) != 1) return 0; buf[disklen] = 0; return 1; } /** inspect header of xfr file, return num_parts */ static int inspect_header(FILE* in) { char zone_buf[3072]; char patname_buf[2048]; uint32_t old_serial, new_serial, num_parts, type; uint64_t time_end_0, time_start_0; uint32_t time_end_1, time_start_1; uint8_t committed; time_t time_end, time_start; if(!xi_diff_read_32(in, &type)) { printf("could not read type, file short\n"); fclose(in); exit(1); } if(type != DIFF_PART_XFRF) { printf("type: %x (BAD FILE TYPE)\n", type); fclose(in); exit(1); } if(!xi_diff_read_8(in, &committed) || !xi_diff_read_32(in, &num_parts) || !xi_diff_read_64(in, &time_end_0) || !xi_diff_read_32(in, &time_end_1) || !xi_diff_read_32(in, &old_serial) || !xi_diff_read_32(in, &new_serial) || !xi_diff_read_64(in, &time_start_0) || !xi_diff_read_32(in, &time_start_1) || !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) || !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) { printf("diff file bad commit part, file too short"); fclose(in); exit(1); } time_end = (time_t)time_end_0; time_start = (time_t)time_start_0; /* printf("type: %x\n", (int)type); */ printf("committed: %d (%s)\n", (int)committed, committed?"yes":"no"); printf("num_parts: %d\n", (int)num_parts); printf("time_end: %d.%6.6d %s", (int)time_end_0, (int)time_end_1, ctime(&time_end)); printf("old_serial: %u\n", (unsigned)old_serial); printf("new_serial: %u\n", (unsigned)new_serial); printf("time_start: %d.%6.6d %s", (int)time_start_0, (int)time_start_1, ctime(&time_start)); printf("zone: %s\n", zone_buf); printf("patname: %s\n", patname_buf); return num_parts; } /** print records in packet */ static void print_records(region_type* region, buffer_type* pkt, int num, int qsection) { domain_table_type* table; int i; rr_type* rr; region_type* tmpregion = region_create(xalloc, free); buffer_type* tmpbuf; if(!tmpregion) { printf("out of memory\n"); return; } tmpbuf = buffer_create(region, QIOBUFSZ); if(!tmpbuf) { printf("out of memory\n"); return; } table = domain_table_create(tmpregion); if(!table) { printf("out of memory\n"); return; } for(i=0; iowner), NULL)); printf("\t%s", rrclass_to_string(rr->klass)); if(rr->type == TYPE_IXFR) printf("\tIXFR\n"); else if(rr->type == TYPE_AXFR) printf("\tAXFR\n"); else printf("\t%s\n", rrtype_to_string(rr->type)); } else { if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) { printf("; cannot print rr %d\n", i); } } } region_destroy(tmpregion); } /** inspect packet (IXFR or AXFR) */ static void inspect_packet(region_type* region, buffer_type* pkt) { printf("\n"); if(buffer_limit(pkt) < QHEADERSZ) { printf("packet too short\n"); return; } printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n", ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"", RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"", AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)), OPCODE(pkt)); printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n", QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt)); buffer_skip(pkt, QHEADERSZ); if(QDCOUNT(pkt) != 0) { printf("; QUESTION SECTION\n"); print_records(region, pkt, QDCOUNT(pkt), 1); } if(ANCOUNT(pkt) != 0) { printf("; ANSWER SECTION\n"); print_records(region, pkt, ANCOUNT(pkt), 0); } if(NSCOUNT(pkt) != 0) { printf("; AUTHORITY SECTION\n"); print_records(region, pkt, NSCOUNT(pkt), 0); } if(ARCOUNT(pkt) != 0) { printf("; ADDITIONAL SECTION\n"); print_records(region, pkt, ARCOUNT(pkt), 0); } } /** inspect part of xfr file */ static void inspect_part(FILE* in, int partnum) { uint32_t pkttype, msglen, msglen2; region_type* region; buffer_type* packet; region = region_create(xalloc, free); if(!region) { printf("out of memory\n"); fclose(in); exit(1); } packet = buffer_create(region, QIOBUFSZ); if(!xi_diff_read_32(in, &pkttype)) { printf("cannot read part %d\n", partnum); fclose(in); exit(1); } if(pkttype != DIFF_PART_XXFR) { printf("bad part %d: not type XXFR\n", partnum); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen)) { printf("bad part %d: not msglen, file too short\n", partnum); fclose(in); exit(1); } if(msglen < QHEADERSZ || msglen > QIOBUFSZ) { printf("bad part %d: msglen %u (too short or too long)\n", partnum, (unsigned)msglen); fclose(in); exit(1); } if(fread(buffer_begin(packet), msglen, 1, in) != 1) { printf("bad part %d: short packet, file too short, %s\n", partnum, strerror(errno)); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen2)) { printf("bad part %d: cannot read msglen2, file too short\n", partnum); fclose(in); exit(1); } if(v==0) { region_destroy(region); return; } printf("\n"); /* printf("type : %x\n", pkttype); */ printf("part : %d\n", partnum); printf("msglen : %u\n", (unsigned)msglen); printf("msglen2 : %u (%s)\n", (unsigned)msglen2, (msglen==msglen2)?"ok":"wrong"); if(v>=2) { buffer_set_limit(packet, msglen); inspect_packet(region, packet); } region_destroy(region); } /** inspect parts of xfr file */ static void inspect_parts(FILE* in, int num) { int i; for(i=0; i QIOBUFSZ) { printf("bad part %d: msglen %u (too short or too long)\n", partnum, (unsigned)msglen); fclose(in); exit(1); } if(fread(buffer_begin(packet), msglen, 1, in) != 1) { printf("bad part %d: short packet, file too short, %s\n", partnum, strerror(errno)); fclose(in); exit(1); } if(!xi_diff_read_32(in, &msglen2)) { printf("bad part %d: cannot read msglen2, file too short\n", partnum); fclose(in); exit(1); } buffer_set_limit(packet, msglen); list_packet(region, packet, partnum); region_destroy(region); } /** list parts of xfr file */ static void list_parts(FILE* in, int num) { int i; for(i=0; i #include "dns.h" #include "namedb.h" struct query; /* * Set of macro's to deal with the dns message header as specified * in RFC1035 in portable way. * */ /* * * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ID | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | QDCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ANCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | NSCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | ARCOUNT | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * */ /* The length of the header */ #define QHEADERSZ 12 /* First octet of flags */ #define RD_MASK 0x01U #define RD_SHIFT 0 #define RD(packet) (*buffer_at((packet), 2) & RD_MASK) #define RD_SET(packet) (*buffer_at((packet), 2) |= RD_MASK) #define RD_CLR(packet) (*buffer_at((packet), 2) &= ~RD_MASK) #define TC_MASK 0x02U #define TC_SHIFT 1 #define TC(packet) (*buffer_at((packet), 2) & TC_MASK) #define TC_SET(packet) (*buffer_at((packet), 2) |= TC_MASK) #define TC_CLR(packet) (*buffer_at((packet), 2) &= ~TC_MASK) #define AA_MASK 0x04U #define AA_SHIFT 2 #define AA(packet) (*buffer_at((packet), 2) & AA_MASK) #define AA_SET(packet) (*buffer_at((packet), 2) |= AA_MASK) #define AA_CLR(packet) (*buffer_at((packet), 2) &= ~AA_MASK) #define OPCODE_MASK 0x78U #define OPCODE_SHIFT 3 #define OPCODE(packet) ((*buffer_at((packet), 2) & OPCODE_MASK) >> OPCODE_SHIFT) #define OPCODE_SET(packet, opcode) \ (*buffer_at((packet), 2) = (*buffer_at((packet), 2) & ~OPCODE_MASK) | ((opcode) << OPCODE_SHIFT)) #define QR_MASK 0x80U #define QR_SHIFT 7 #define QR(packet) (*buffer_at((packet), 2) & QR_MASK) #define QR_SET(packet) (*buffer_at((packet), 2) |= QR_MASK) #define QR_CLR(packet) (*buffer_at((packet), 2) &= ~QR_MASK) /* Second octet of flags */ #define RCODE_MASK 0x0fU #define RCODE_SHIFT 0 #define RCODE(packet) (*buffer_at((packet), 3) & RCODE_MASK) #define RCODE_SET(packet, rcode) \ (*buffer_at((packet), 3) = (*buffer_at((packet), 3) & ~RCODE_MASK) | (rcode)) #define CD_MASK 0x10U #define CD_SHIFT 4 #define CD(packet) (*buffer_at((packet), 3) & CD_MASK) #define CD_SET(packet) (*buffer_at((packet), 3) |= CD_MASK) #define CD_CLR(packet) (*buffer_at((packet), 3) &= ~CD_MASK) #define AD_MASK 0x20U #define AD_SHIFT 5 #define AD(packet) (*buffer_at((packet), 3) & AD_MASK) #define AD_SET(packet) (*buffer_at((packet), 3) |= AD_MASK) #define AD_CLR(packet) (*buffer_at((packet), 3) &= ~AD_MASK) #define Z_MASK 0x40U #define Z_SHIFT 6 #define Z(packet) (*buffer_at((packet), 3) & Z_MASK) #define Z_SET(packet) (*buffer_at((packet), 3) |= Z_MASK) #define Z_CLR(packet) (*buffer_at((packet), 3) &= ~Z_MASK) #define RA_MASK 0x80U #define RA_SHIFT 7 #define RA(packet) (*buffer_at((packet), 3) & RA_MASK) #define RA_SET(packet) (*buffer_at((packet), 3) |= RA_MASK) #define RA_CLR(packet) (*buffer_at((packet), 3) &= ~RA_MASK) /* Query ID */ #define ID(packet) (buffer_read_u16_at((packet), 0)) #define ID_SET(packet, id) (buffer_write_u16_at((packet), 0, (id))) /* Flags, RCODE, and OPCODE. */ #define FLAGS(packet) (buffer_read_u16_at((packet), 2)) #define FLAGS_SET(packet, f) (buffer_write_u16_at((packet), 2, (f))) /* Counter of the question section */ #define QDCOUNT(packet) (buffer_read_u16_at((packet), 4)) #define QDCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 4, (c))) /* Counter of the answer section */ #define ANCOUNT(packet) (buffer_read_u16_at((packet), 6)) #define ANCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 6, (c))) /* Counter of the authority section */ #define NSCOUNT(packet) (buffer_read_u16_at((packet), 8)) #define NSCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 8, (c))) /* Counter of the additional section */ #define ARCOUNT(packet) (buffer_read_u16_at((packet), 10)) #define ARCOUNT_SET(packet, c) (buffer_write_u16_at((packet), 10, (c))) /* Miscellaneous limits */ #define MAX_PACKET_SIZE 65535 /* Maximum supported size of DNS packets. */ #define QIOBUFSZ (MAX_PACKET_SIZE + MAX_RR_SIZE) #define MAXRRSPP 10240 /* Maximum number of rr's per packet */ #define MAX_COMPRESSED_DNAMES MAXRRSPP /* Maximum number of compressed domains. */ #define MAX_COMPRESSION_OFFSET 16383 /* Compression pointers are 14 bit. */ #define IPV4_MINIMAL_RESPONSE_SIZE 1480 /* Recommended minimal edns size for IPv4 */ #define IPV6_MINIMAL_RESPONSE_SIZE 1220 /* Recommended minimal edns size for IPv6 */ /* use round robin rotation */ extern int round_robin; /* use minimal responses (more minimal, with additional only for referrals) */ extern int minimal_responses; /* * Encode RR with OWNER as owner name into QUERY. Returns the number * of RRs successfully encoded. */ int packet_encode_rr(struct query *query, domain_type *owner, rr_type *rr, uint32_t ttl); /* * Encode RRSET with OWNER as the owner name into QUERY. Returns the * number of RRs successfully encoded. If TRUNCATE_RRSET the entire * RRset is truncated in case an RR (or the RRsets signature) does not * fit. */ int packet_encode_rrset(struct query *query, domain_type *owner, rrset_type *rrset, int truncate_rrset, size_t minimal_respsize, int* done); /* * Skip the RR at the current position in PACKET. */ int packet_skip_rr(buffer_type *packet, int question_section); /* * Skip the dname at the current position in PACKET. */ int packet_skip_dname(buffer_type *packet); /* * Read the RR at the current position in PACKET. */ rr_type *packet_read_rr(region_type *region, domain_table_type *owners, buffer_type *packet, int question_section); /* * read a query entry from network packet given in buffer. * does not follow compression ptrs, checks for errors (returns 0). * Dest must be at least MAXDOMAINLEN long. */ int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass); /* read notify SOA serial from packet. buffer position is unmodified on return. * returns false on no-serial found or parse failure. */ int packet_find_notify_serial(buffer_type *packet, uint32_t* serial); #endif /* _PACKET_H_ */ nsd-4.1.26/udb.h0000664000175000017500000006300112671762455012770 0ustar wouterwouter/* udb.h - u(micro) data base, stores data and index information in mmap file. * By W.C.A. Wijngaards * Copyright 2010, NLnet Labs. * BSD, see LICENSE. */ #ifndef UDB_H #define UDB_H #include /** * The micro data base UDB. * * File data.udb is mmapped and used to lookup and edit. * it contains a header with space-allocation-info, and a reference to the * base information, an object that is the entry point for the file. * Then it contains a lot of data and index objects. * * The space allocator is 'buddy system', 1megareas, larger get own area. * So worst case is 2xdata filesize (+header). Growth semi-linear. * Chunks have size and type (for recovery). Call to reserve space. * Call to 'realloc-in-place', if space permits. * * Usually you want a record-type and its indexes (sorted) to be stored in * the file. This is a table (named by string). The record is opaque * data. * * To be able to use pointers in the mmapped file, there is conversion of * relative-pointers(to file base) to system-pointers. * * If an item is moved its internal pointers need to be recalculated. * Thus a recordtype (that has internal pointers) must provide a routine. * Structures that are 'on-disk', are denoted with _d. Except rel_ptr which * is also on-disk. * * About 64-bit trouble. The pointer-size which which the application is * compiled determines the file layout, because this makes it perform well * in a mmap. It could in theory be converted if you really wanted to. * Nonpointer data is best stored as a fixed bitsize (uint8, 16, 32, 64). */ typedef struct udb_base udb_base; typedef struct udb_alloc udb_alloc; /** these checks are very slow, disabled by default */ #if 0 /** perform extra checks (when --enable-checking is used) */ #ifndef NDEBUG #define UDB_CHECK 1 #endif #endif /** pointers are stored like this */ typedef uint64_t udb_void; /** convert relptr to usable pointer */ #define UDB_REL(base, relptr) ((base) + (relptr)) /** from system pointer to relative pointer */ #define UDB_SYSTOREL(base, ptr) ((udb_void)((void*)(ptr) - (base))) /** MAX 2**x exponent of alloced chunks, for 1Mbytes. The smallest * chunk is 16bytes (8preamble+8data), so 0-3 is unused. */ #define UDB_ALLOC_CHUNKS_MAX 20 /** size of areas that are subdivided */ #define UDB_ALLOC_CHUNK_SIZE ((uint64_t)1<= amount. */ int udb_exp_size(uint64_t amount); /** * Utility for alloc, what is the size that the current offset supports * as a maximum 2**x chunk. * Does not work for offset = 0 (result is infinite). * @param offset: the offset into the memory region. * @return maximum exponent where 2**x is fits the offset, thus * offset % (2**x) == 0 and x cannot be larger. */ int udb_exp_offset(uint64_t offset); /** * Convert pointer to the data part to a pointer to the base of the chunk. * @param data: data part. * @return pointer to the base of the chunk. */ udb_void chunk_from_dataptr_ext(udb_void data); /** * Create empty UDB allocate structure to write to disk to initialize file. * @param a: allocation structure to initialize. system pointer. */ void udb_alloc_init_new(udb_alloc_d* a); /** * Create new udb allocator, with specific data on disk * @param udb: the udb. * @param disk: disk data. * @return udb allocator or NULL on (malloc) failure. */ udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk); /** * Free the udb allocator from memory. * @param alloc: the udb space allocator. */ void udb_alloc_delete(udb_alloc* alloc); /** * Allocate space on the disk. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param sz: size you want to use. * @return relative pointer (or 0 on alloc failure). */ udb_void udb_alloc_space(udb_alloc* alloc, size_t sz); /** * Allocate space on disk, give already the data you want there. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param d: data you want there (system pointer). * @param sz: size you want to use. * @return relative pointer (or 0 on alloc failure). */ udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz); /** * free allocated space. It may shrink the file. * This may involve closing and reopening the mmap. * @param alloc: the udb space allocator. * @param r: relative pointer to data you want to free. * @param sz: the size of the data you stop using. * @return false if the free failed, it failed the close and mmap. */ int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz); /** * realloc an existing allocated space. It may grow the file. * This may involve closing and reopening the mmap. * It could also use the existing space where it is now. * @param alloc: the udb space allocator. * @param r: relative pointer to data you want to realloc. * if 0 then this is alloc_space(), and osz is ignored. * @param osz: the old size of the data. * @param sz: the size of the data you want to get. * if this is 0 then a free() is done, but please do it directly, * as you then get a returnvalue (file errors). * @return relative pointer (0 on alloc failure, same if not moved). */ udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz, size_t sz); /** * Prepare for a lot of new entries. Grow space for that. * This can involve closing and reopening the mmap. * This space (if large) is going to be released on next free() or close(). * @param alloc: the udb space allocator. * @param sz: size of the entries. * @param num: number of entries. * @return false on failure to grow or re-mmap. */ int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num); /** * attempt to compact the data and move free space to the end * can shrink the db, which calls sync on the db (for portability). * @param udb: the udb base. * @return 0 on failure (to remap the (possibly) changed udb base). */ int udb_compact(udb_base* udb); /** * set the udb to inhibit or uninhibit compaction. Does not perform * the compaction itself if enabled, for that call udb_compact. * @param udb: the udb base * @param inhibit: 0 or 1. */ void udb_compact_inhibited(udb_base* udb, int inhibit); /** * Set the alloc type for a newly alloced piece of data * @param alloc: the udb space allocator. * @param r: relativeptr to the data. * @param tp: the type of that block. */ void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp); /** * See if a pointer could be valid (it points within valid space), * for the given type side. For debug checks. * @param udb: the udb * @param to: the ptr (offset). * @param destsize: the size_of of the destination of the pointer. * @return true if it points to a valid region. */ int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize); /** * See if a pointer is valid (it points to a chunk). For debug checks. * @param udb: the udb. * @param to: the ptr (offset). * @return true if it points to the start of a chunks data region. */ int udb_valid_dataptr(udb_base* udb, udb_void to); /** * See if a pointer is on the relptrlist for dataptr. For debug checks. * @param udb: the udb. * @param rptr: the rel_ptr (offset). * @param to: dataptr of the chunk on which ptrlist the rptr is searched. * @return true if rptr is valid and on the ptrlist. */ int udb_valid_rptr(udb_base* udb, udb_void rptr, udb_void to); /*** UDB_REL_PTR ***/ /** * Init a new UDB rel ptr at NULL. * @param ptr: sysptr, becomes inited. */ void udb_rel_ptr_init(udb_rel_ptr* ptr); /** * Unlink a UDB rel ptr. * @param base: the udb base * @param ptr: sysptr, unlinked */ void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr); /** * Link a UDB rel ptr to a new chunk * @param base: the udb base * @param ptr: sysptr, linked to new value. * @param to: the data to point to (relative ptr). */ void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to); /** * Change rel ptr to a new value (point to another record) * @param base: the udb base * @param ptr: sysptr, points to new value. * @param to: the data to point to (relative ptr). */ void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to); /** * A chunk has moved and now edit all the relptrs in list to fix them up * @param base: the udb base * @param list: start of the ptr list * @param to: where the chunk has moved to relptr to its userdata. */ void udb_rel_ptr_edit(void* base, udb_void list, udb_void to); /** * Get system pointer. Assumes there is a variable named 'base' * that points to the udb base. * @param ptr: the relative pointer (a sysptr to it). * @return void* to the data. */ #define UDB_SYSPTR(ptr) UDB_REL(base, (ptr)->data) /** get sys ptr for char* string */ #define UDB_CHAR(ptr) ((char*)UDB_REL(base, ptr)) /** get sys ptr for udb_rel_ptr */ #define UDB_REL_PTR(ptr) ((udb_rel_ptr*)UDB_REL(base, ptr)) /** get sys ptr for udb_glob_d */ #define UDB_GLOB(ptr) ((udb_glob_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_chunk_d */ #define UDB_CHUNK(ptr) ((udb_chunk_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_free_chunk_d */ #define UDB_FREE_CHUNK(ptr) ((udb_free_chunk_d*)UDB_REL(base, ptr)) /** get sys ptr for udb_xl_chunk_d */ #define UDB_XL_CHUNK(ptr) ((udb_xl_chunk_d*)UDB_REL(base, ptr)) /* udb_ptr */ /** * Initialize an udb ptr. Set to NULL. (and thus not linked can be deleted). * You MUST set it to 0 before you stop using the ptr. * @param ptr: the ptr to initialise (caller has allocated it). * @param udb: the udb base to link it to. */ void udb_ptr_init(udb_ptr* ptr, udb_base* udb); /** * Set udp ptr to a new value. If set to NULL you can delete it. * @param ptr: the ptr. * @param udb: the udb base to link up with that data segment's administration. * @param newval: new value to point to (udb_void relative file offset to data). */ void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval); /** dereference udb_ptr */ #define UDB_PTR(ptr) (UDB_REL(*((ptr)->base), (ptr)->data)) /** * Ease of use udb ptr, allocate space and return ptr to it * You MUST udb_ptr_set it to 0 before you stop using the ptr. * @param base: udb base to use. * @param ptr: ptr is overwritten, can be uninitialised. * @param type: type of the allocation. * You need a special type if the block contains udb_rel_ptr's. * You can use udb_type_data for plain data. * @param sz: amount to allocate. * @return 0 on alloc failure. */ int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type, size_t sz); /** * Ease of use udb ptr, free space and set ptr to NULL (to it can be deleted). * The space is freed on disk. * @param ptr: the ptr. * @param udb: udb base. * @param sz: the size of the data you stop using. */ void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz); /** * Get pointer to the data of the ptr. or use a macro to cast UDB_PTR to * the type of your structure(.._d) */ static inline uint8_t* udb_ptr_data(udb_ptr* ptr) { return (uint8_t*)UDB_PTR(ptr); } /** * See if udb ptr is null */ static inline int udb_ptr_is_null(udb_ptr* ptr) { return (ptr->data == 0); } /** * Get the type of a udb_ptr chunk. * @param ptr: udb pointer * @return type of chunk */ udb_chunk_type udb_ptr_get_type(udb_ptr* ptr); /** Ease of use, create new pointer to destination relptr * You MUST udb_ptr_set it to 0 before you stop using the ptr. */ static inline void udb_ptr_new(udb_ptr* ptr, udb_base* udb, udb_rel_ptr* d) { udb_ptr_init(ptr, udb); udb_ptr_set(ptr, udb, d->data); } /** Ease of use. Stop using this ptr */ static inline void udb_ptr_unlink(udb_ptr* ptr, udb_base* udb) { if(ptr->data) udb_base_unlink_ptr(udb, ptr); } /* Ease of use. Assign rptr from rptr */ static inline void udb_rptr_set_rptr(udb_rel_ptr* dest, udb_base* udb, udb_rel_ptr* p) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } if(p->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, p), p->data)); } #endif udb_rel_ptr_set(udb->base, dest, p->data); } /* Ease of use. Assign rptr from ptr */ static inline void udb_rptr_set_ptr(udb_rel_ptr* dest, udb_base* udb, udb_ptr* p) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } if(p->data) { assert(udb_valid_dataptr(udb, p->data)); } #endif udb_rel_ptr_set(udb->base, dest, p->data); } /* Ease of use. Assign ptr from rptr */ static inline void udb_ptr_set_rptr(udb_ptr* dest, udb_base* udb, udb_rel_ptr* p) { #ifdef UDB_CHECK if(p->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, p), p->data)); } #endif udb_ptr_set(dest, udb, p->data); } /* Ease of use. Assign ptr from ptr */ static inline void udb_ptr_set_ptr(udb_ptr* dest, udb_base* udb, udb_ptr* p) { udb_ptr_set(dest, udb, p->data); } /* Ease of use, zero rptr. You use this to zero an existing pointer. * A new rptr should be rel_ptr_init-ed before it is taken into use. */ static inline void udb_rptr_zero(udb_rel_ptr* dest, udb_base* udb) { #ifdef UDB_CHECK if(dest->data) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, dest), dest->data)); } #endif udb_rel_ptr_set(udb->base, dest, 0); } /* Ease of use, zero ptr */ static inline void udb_ptr_zero(udb_ptr* dest, udb_base* udb) { udb_ptr_set(dest, udb, 0); } /** ease of use, delete memory pointed at by relptr */ static inline void udb_rel_ptr_free_space(udb_rel_ptr* ptr, udb_base* udb, size_t sz) { udb_void d = ptr->data; #ifdef UDB_CHECK if(d) { assert(udb_valid_rptr(udb, UDB_SYSTOREL(udb->base, ptr), d)); } #endif udb_rel_ptr_set(udb->base, ptr, 0); udb_alloc_free(udb->alloc, d, sz); } #endif /* UDB_H */ nsd-4.1.26/xfrd-notify.h0000664000175000017500000000552413212010210014434 0ustar wouterwouter/* * xfrd-notify.h - notify sending routines. * * Copyright (c) 2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_NOTIFY_H #define XFRD_NOTIFY_H #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "tsig.h" #include "rbtree.h" struct nsd; struct region; struct xfrd_zone; struct zone_options; struct zone; 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. */ struct notify_zone { rbnode_type node; /* name of the zone */ const dname_type* apex; const char* apex_str; tsig_record_type notify_tsig; /* tsig state for notify */ struct zone_options* options; struct xfrd_soa *current_soa; /* current SOA in NSD */ /* notify sending handler */ /* 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 */ 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, struct zone_options* options); /* delete notify zone */ void xfrd_del_notify(struct xfrd_state* xfrd, const dname_type* dname); /* send notifications to all in the notify list */ void xfrd_send_notify(rbtree_type* tree, const struct dname* apex, struct xfrd_soa* new_soa); /* start notifications, if not started already (does not clobber SOA) */ void xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd); /* handle soa update notify for a master zone. newsoa can be NULL. Makes sure that the soa (serial) has changed. Or drops notify. */ void notify_handle_master_zone_soainfo(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa); /* close fds in use for notification sending */ void close_notify_fds(rbtree_type* tree); /* stop send of notify */ void notify_disable(struct notify_zone* zone); #endif /* XFRD_NOTIFY_H */ nsd-4.1.26/radtree.h0000664000175000017500000001604013151271637013634 0ustar wouterwouter/* * radtree -- generic radix tree for binary strings. * * Copyright (c) 2010, NLnet Labs. See LICENSE for license. */ #ifndef RADTREE_H #define RADTREE_H struct radnode; struct region; /** length of the binary string */ typedef uint16_t radstrlen_type; /** * The radix tree * * The elements are stored based on binary strings(0-255) of a given length. * They are sorted, a prefix is sorted before its suffixes. * If you want to know the key string, you should store it yourself, the * tree stores it in the parts necessary for lookup. * For binary strings for domain names see the radname routines. */ struct radtree { /** root node in tree */ struct radnode* root; /** count of number of elements */ size_t count; /** region for allocation */ struct region* region; }; /** * A radix tree lookup node. * The array is malloced separately from the radnode. */ struct radnode { /** data element associated with the binary string up to this node */ void* elem; /** parent node (NULL for the root) */ struct radnode* parent; /** index in the parent lookup array */ uint8_t pidx; /** offset of the lookup array, add to [i] for lookups */ uint8_t offset; /** length of the lookup array */ uint16_t len; /** capacity of the lookup array (can be larger than length) */ uint16_t capacity; /** the lookup array by [byte-offset] */ struct radsel* array; } ATTR_PACKED; /** * radix select edge in array */ struct radsel { /** additional string after the selection-byte for this edge. */ uint8_t* str; /** length of the additional string for this edge */ radstrlen_type len; /** node that deals with byte+str */ struct radnode* node; } ATTR_PACKED; /** * Create new radix tree * @param region: where to allocate the tree. * @return new tree or NULL on alloc failure. */ struct radtree* radix_tree_create(struct region* region); /** * Init new radix tree. * @param rt: radix tree to be initialized. */ void radix_tree_init(struct radtree* rt); /** * Delete intermediate nodes from radix tree * @param rt: radix tree to be initialized. */ void radix_tree_clear(struct radtree* rt); /** * Delete radix tree. * @param rt: radix tree to be deleted. */ void radix_tree_delete(struct radtree* rt); /** * Insert element into radix tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @param elem: pointer to element data. * @return NULL on failure - out of memory. * NULL on failure - duplicate entry. * On success the new radix node for this element. */ struct radnode* radix_insert(struct radtree* rt, uint8_t* k, radstrlen_type len, void* elem); /** * Delete element from radix tree. * @param rt: the radix tree. * @param n: radix node for that element. * if NULL, nothing is deleted. */ void radix_delete(struct radtree* rt, struct radnode* n); /** * Find radix element in tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @return the radix node or NULL if not found. */ struct radnode* radix_search(struct radtree* rt, uint8_t* k, radstrlen_type len); /** * Find radix element in tree, and if not found, find the closest smaller or * equal element in the tree. * @param rt: the radix tree. * @param key: key string. * @param len: length of key. * @param result: returns the radix node or closest match (NULL if key is * smaller than the smallest key in the tree). * @return true if exact match, false if no match. */ int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result); /** * Return the first (smallest) element in the tree. * @param rt: the radix tree. * @return: first node or NULL if none. */ struct radnode* radix_first(struct radtree* rt); /** * Return the last (largest) element in the tree. * @param rt: the radix tree. * @return: last node or NULL if none. */ struct radnode* radix_last(struct radtree* rt); /** * Return the next element. * @param n: the element to go from. * @return: next node or NULL if none. */ struct radnode* radix_next(struct radnode* n); /** * Return the previous element. * @param n: the element to go from. * @return: prev node or NULL if none. */ struct radnode* radix_prev(struct radnode* n); /* * Perform a walk through all elements of the tree. * node: variable of type struct radnode*. * tree: pointer to the tree. * for(node=radix_first(tree); node; node=radix_next(node)) */ /** * Create a binary string to represent a domain name * @param k: string buffer to store into * @param len: output length, initially, the max, output the result. * @param dname: the domain name to convert, in wireformat. * @param dlen: length of space for dname. */ void radname_d2r(uint8_t* k, radstrlen_type* len, const uint8_t* dname, size_t dlen); /** * Convert a binary string back to a domain name. * @param k: the binary string. * @param len: length of k. * @param dname: buffer to store domain name into. * @param dlen: length of dname (including root label). */ void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen); /** * Search the radix tree using a domain name. * The name is internally converted to a radname. * @param rt: tree * @param d: domain name, no compression pointers allowed. * @param max: max length to go from d. * @return NULL on parse error or if not found. */ struct radnode* radname_search(struct radtree* rt, const uint8_t* d, size_t max); /** * Find radix element in tree by domain name, and if not found, * find the closest smaller or equal element in the tree. * The name is internally converted to a radname (same sorting order). * @param rt: the radix tree. * @param d: domain name, no compression pointers allowed. * @param max: max length to go from d. * @param result: returns the radix node or closest match (NULL if key is * smaller than the smallest key in the tree). * could result in NULL on a parse error as well (with return false). * @return true if exact match, false if no match. */ int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max, struct radnode** result); /** * Insert radix element by domain name. * @param rt: the radix tree * @param d: domain name, no compression pointers. * @param max: max length from d. * @param elem: the element pointer to insert. * @return NULL on failure - out of memory. * NULL on failure - duplicate entry. * NULL on failure - parse error. * On success the radix node for this element. */ struct radnode* radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem); /** * Delete element by domain name from radix tree. * @param rt: the radix tree. * @param d: the domain name. If it is not in the tree nothing happens. * @param max: max length. */ void radname_delete(struct radtree* rt, const uint8_t* d, size_t max); /** number of bytes in common in strings */ radstrlen_type bstr_common_ext(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen); /** true if one is prefix of the other */ int bstr_is_prefix_ext(uint8_t* p, radstrlen_type plen, uint8_t* x, radstrlen_type xlen); #endif /* RADTREE_H */ nsd-4.1.26/tsig-openssl.c0000664000175000017500000000710412766507052014635 0ustar wouterwouter/* * tsig-openssl.h -- Interface to OpenSSL for TSIG support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #if defined(HAVE_SSL) #include "tsig-openssl.h" #include "tsig.h" #include "util.h" static void *create_context(region_type *region); static void init_context(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key); static void update(void *context, const void *data, size_t size); static void final(void *context, uint8_t *digest, size_t *size); static int tsig_openssl_init_algorithm(region_type* region, const char* digest, const char* name, const char* wireformat) { tsig_algorithm_type* algorithm; const EVP_MD *hmac_algorithm; hmac_algorithm = EVP_get_digestbyname(digest); if (!hmac_algorithm) { /* skip but don't error */ return 0; } algorithm = (tsig_algorithm_type *) region_alloc( region, sizeof(tsig_algorithm_type)); algorithm->short_name = name; algorithm->wireformat_name = dname_parse(region, wireformat); if (!algorithm->wireformat_name) { log_msg(LOG_ERR, "cannot parse %s algorithm", wireformat); return 0; } algorithm->maximum_digest_size = EVP_MD_size(hmac_algorithm); if(algorithm->maximum_digest_size < 20) algorithm->maximum_digest_size = EVP_MAX_MD_SIZE; algorithm->data = hmac_algorithm; algorithm->hmac_create_context = create_context; algorithm->hmac_init_context = init_context; algorithm->hmac_update = update; algorithm->hmac_final = final; tsig_add_algorithm(algorithm); return 1; } int tsig_openssl_init(region_type *region) { int count = 0; #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_digests(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); #endif count += tsig_openssl_init_algorithm(region, "md5", "hmac-md5","hmac-md5.sig-alg.reg.int."); count += tsig_openssl_init_algorithm(region, "sha1", "hmac-sha1", "hmac-sha1."); count += tsig_openssl_init_algorithm(region, "sha224", "hmac-sha224", "hmac-sha224."); count += tsig_openssl_init_algorithm(region, "sha256", "hmac-sha256", "hmac-sha256."); count += tsig_openssl_init_algorithm(region, "sha384", "hmac-sha384", "hmac-sha384."); count += tsig_openssl_init_algorithm(region, "sha512", "hmac-sha512", "hmac-sha512."); return count; } static void cleanup_context(void *data) { HMAC_CTX *context = (HMAC_CTX *) data; #ifdef HAVE_HMAC_CTX_NEW HMAC_CTX_free(context); #else HMAC_CTX_cleanup(context); free(context); #endif } static void * create_context(region_type *region) { #ifdef HAVE_HMAC_CTX_NEW HMAC_CTX *context = HMAC_CTX_new(); #else HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX)); #endif region_add_cleanup(region, cleanup_context, context); #ifdef HAVE_HMAC_CTX_RESET HMAC_CTX_reset(context); #else HMAC_CTX_init(context); #endif return context; } static void init_context(void *context, tsig_algorithm_type *algorithm, tsig_key_type *key) { HMAC_CTX *ctx = (HMAC_CTX *) context; const EVP_MD *md = (const EVP_MD *) algorithm->data; HMAC_Init_ex(ctx, key->data, key->size, md, NULL); } static void update(void *context, const void *data, size_t size) { HMAC_CTX *ctx = (HMAC_CTX *) context; HMAC_Update(ctx, (unsigned char *) data, (int) size); } static void final(void *context, uint8_t *digest, size_t *size) { HMAC_CTX *ctx = (HMAC_CTX *) context; unsigned len = (unsigned) *size; HMAC_Final(ctx, digest, &len); *size = (size_t) len; } void tsig_openssl_finalize() { #ifdef HAVE_EVP_CLEANUP EVP_cleanup(); #endif } #endif /* defined(HAVE_SSL) */ nsd-4.1.26/configure0000775000175000017500000105341413401455024013743 0ustar wouterwouter#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for NSD 4.1.26. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: nsd-bugs@nlnetlabs.nl about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' PACKAGE_VERSION='4.1.26' PACKAGE_STRING='NSD 4.1.26' PACKAGE_BUGREPORT='nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS DNSTAP_OBJ DNSTAP_SRC opt_dnstap_socket_path ENABLE_DNSTAP PROTOC_C SSL_LIBS HAVE_SSL ratelimit_default ratelimit LIBOBJS YFLAGS YACC LEXLIB LEX_OUTPUT_ROOT LEX INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM LN_S AWK user chrootdir xfrdir zonelistfile xfrdfile zonesdir piddir dbdir dbfile pidfile logfile nsd_conf_file configdir EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_configdir with_nsd_conf_file with_logfile with_pidfile with_dbfile with_zonesdir with_xfrdfile with_zonelistfile with_xfrdir with_chroot with_user enable_flto enable_pie enable_relro_now with_libevent enable_largefile enable_recvmmsg with_facility with_tcp_timeout enable_root_server enable_ipv6 enable_bind8_stats enable_zone_stats enable_checking enable_memclean enable_ratelimit enable_ratelimit_default_is_off with_ssl enable_nsec3 enable_minimal_responses enable_mmap enable_radix_tree enable_packed enable_dnstap with_dnstap_socket_path with_protobuf_c with_libfstrm enable_systemd ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP YACC YFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures NSD 4.1.26 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/nsd] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of NSD 4.1.26:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-flto Disable link-time optimization (gcc specific option) --enable-pie Enable Position-Independent Executable (eg. to fully benefit from ASLR, small performance penalty) --enable-relro-now Enable full relocation binding at load-time (RELRO NOW, to protect GOT and .dtor areas) --disable-largefile omit support for large files --enable-recvmmsg Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems for IPv6 --enable-root-server Configure NSD as a root server --disable-ipv6 Disables IPv6 support --enable-bind8-stats Enables BIND8 like NSTATS & XSTATS and statistics in nsd-control --enable-zone-stats Enable per-zone statistics gathering (needs --enable-bind8-stats) --enable-checking Enable internal runtime checks --enable-memclean Cleanup memory (at exit) for eg. valgrind, memcheck --enable-ratelimit Enable rate limiting --enable-ratelimit-default-is-off Enable this to set default of ratelimit to off (enable in nsd.conf), otherwise ratelimit is enabled by default if --enable-ratelimit is enabled --disable-nsec3 Disable NSEC3 support --disable-minimal-responses Disable response minimization. More truncation. --enable-mmap Use mmap instead of malloc. Experimental. --disable-radix-tree You can disable the radix tree and use the red-black tree for the main lookups, the red-black tree uses less memory, but uses some more CPU. --enable-packed Enable packed structure alignment, uses less memory, but unaligned reads. --enable-dnstap Enable dnstap support (requires fstrm, protobuf-c) --enable-systemd compile with systemd support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-configdir=dir NSD configuration directory --with-nsd_conf_file=path Pathname to the NSD configuration file --with-logfile=path Pathname to the default log file --with-pidfile=path Pathname to the NSD pidfile --with-dbfile=path Pathname to the NSD database --with-zonesdir=dir NSD default location for zone files --with-xfrdfile=path Pathname to the NSD xfrd zone timer state file --with-zonelistfile=path Pathname to the NSD zone list file --with-xfrdir=path Pathname to where the NSD transfer dir is created --with-chroot=dir NSD default chroot directory --with-user=username User name or ID to answer the queries with --with-libevent=pathname use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr or you can specify an explicit path), useful when the zone count is high. --with-facility=name Syslog default facility (LOG_DAEMON) --with-tcp-timeout=number Limit the default tcp timeout --with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr) --with-dnstap-socket-path=pathname set default dnstap socket path --with-protobuf-c=path Path where protobuf-c is installed, for dnstap --with-libfstrm=path Path where libfstrm is installed, for dnstap Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF NSD configure 4.1.26 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------ ## ## Report this to nsd-bugs@nlnetlabs.nl ## ## ------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by NSD $as_me 4.1.26, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" CFLAGS="$CFLAGS" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= fi if test "$MINIX" = yes; then $as_echo "#define _POSIX_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h $as_echo "#define _MINIX 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_safe_to_define___extensions__=yes else ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 $as_echo "$ac_cv_safe_to_define___extensions__" >&6; } test $ac_cv_safe_to_define___extensions__ = yes && $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h $as_echo "#define _ALL_SOURCE 1" >>confdefs.h $as_echo "#define _GNU_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h if test "$ac_cv_header_minix_config_h" = "yes"; then $as_echo "#define _NETBSD_SOURCE 1" >>confdefs.h fi case "$prefix" in NONE) case "$sysconfdir" in '${prefix}/etc') sysconfdir=/etc ;; esac case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac ;; esac # # Determine configuration directory # configdir=$sysconfdir/nsd # Check whether --with-configdir was given. if test "${with_configdir+set}" = set; then : withval=$with_configdir; configdir=$withval fi cat >>confdefs.h <<_ACEOF #define CONFIGDIR "`eval echo $configdir`" _ACEOF # # Determine configuration file nsd_conf_file=${configdir}/nsd.conf # Check whether --with-nsd_conf_file was given. if test "${with_nsd_conf_file+set}" = set; then : withval=$with_nsd_conf_file; nsd_conf_file=$withval fi # the eval is to evaluate shell expansion twice, once # for $nsd_conf_file and once for the ${prefix} within it. cat >>confdefs.h <<_ACEOF #define CONFIGFILE "`eval echo $nsd_conf_file`" _ACEOF # # Default logfile # logfile=${localstatedir}/log/nsd.log # Check whether --with-logfile was given. if test "${with_logfile+set}" = set; then : withval=$with_logfile; logfile=$withval fi # # Database directory # dbdir=${localstatedir}/db/nsd # # Determine the pidfile location. Check if /var/run exists, if so set pidfile # to /var/run/nsd.pid by default # if test -d ${localstatedir}/run; then pidfile=${localstatedir}/run/nsd.pid else pidfile=${dbdir}/nsd.pid fi # Check whether --with-pidfile was given. if test "${with_pidfile+set}" = set; then : withval=$with_pidfile; pidfile=$withval fi cat >>confdefs.h <<_ACEOF #define PIDFILE "`eval echo $pidfile`" _ACEOF # # Determine location of nsd.db # dbfile=${dbdir}/nsd.db # Check whether --with-dbfile was given. if test "${with_dbfile+set}" = set; then : withval=$with_dbfile; dbfile=$withval fi cat >>confdefs.h <<_ACEOF #define DBFILE "`eval echo $dbfile`" _ACEOF if test -n "$dbfile"; then dbdir=`dirname $dbfile` fi piddir=`dirname $pidfile` # # Determine the default directory for the zone files # zonesdir=$configdir # Check whether --with-zonesdir was given. if test "${with_zonesdir+set}" = set; then : withval=$with_zonesdir; zonesdir=$withval fi cat >>confdefs.h <<_ACEOF #define ZONESDIR "`eval echo $zonesdir`" _ACEOF # default xfrd file location. xfrdfile=${dbdir}/xfrd.state # Check whether --with-xfrdfile was given. if test "${with_xfrdfile+set}" = set; then : withval=$with_xfrdfile; xfrdfile=$withval fi cat >>confdefs.h <<_ACEOF #define XFRDFILE "`eval echo $xfrdfile`" _ACEOF # default zonelist file location. zonelistfile=${dbdir}/zone.list # Check whether --with-zonelistfile was given. if test "${with_zonelistfile+set}" = set; then : withval=$with_zonelistfile; zonelistfile=$withval fi cat >>confdefs.h <<_ACEOF #define ZONELISTFILE "`eval echo $zonelistfile`" _ACEOF # default xfr dir location. xfrdir="/tmp" # Check whether --with-xfrdir was given. if test "${with_xfrdir+set}" = set; then : withval=$with_xfrdir; xfrdir=$withval fi cat >>confdefs.h <<_ACEOF #define XFRDIR "`eval echo $xfrdir`" _ACEOF # nsd sbin location. tmpinstantiate execprefix with defaults if not yet done. if test "x${exec_prefix}" = "xNONE"; then if test "x${prefix}" = "xNONE"; then exec_prefix="$ac_default_prefix" else exec_prefix="${prefix}"; fi nsd_start_path="`eval echo $sbindir`/nsd" exec_prefix="NONE" else nsd_start_path="`eval echo $sbindir`/nsd" fi cat >>confdefs.h <<_ACEOF #define NSD_START_PATH "$nsd_start_path" _ACEOF # # Determine default chroot directory # # Check whether --with-chroot was given. if test "${with_chroot+set}" = set; then : withval=$with_chroot; chrootdir=$withval cat >>confdefs.h <<_ACEOF #define CHROOTDIR "`eval echo $chrootdir`" _ACEOF fi # # Determine the user name to drop privileges to # user=nsd # Check whether --with-user was given. if test "${with_user+set}" = set; then : withval=$with_user; user=$withval fi cat >>confdefs.h <<_ACEOF #define USER "$user" _ACEOF # Checks for programs. for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_YACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 $as_echo "$YACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" if test "$LEX" != ":" -a "$LEX" != ""; then # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, # but later could define it as a macro and then we should not redefine it. { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lex defines yy_current_buffer" >&5 $as_echo_n "checking if lex defines yy_current_buffer... " >&6; } cat <conftest.lex %% EOF $LEX -i -t conftest.lex >> conftest.c if grep "^#define yy_current_buffer" conftest.c >/dev/null; then cat >>confdefs.h <<_ACEOF #define LEX_DEFINES_YY_CURRENT_BUFFER 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest.lex conftest.c fi # Checks for typedefs, structures, and compiler characteristics. # allow user to override the -g -O2 flags. if test "x$CFLAGS" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -g" >&5 $as_echo_n "checking whether $CC supports -g... " >&6; } cache=`echo g | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -g -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -g" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi # we do not use O3 because it causes miscompilations. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -O2" >&5 $as_echo_n "checking whether $CC supports -O2... " >&6; } cache=`echo O2 | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -O2 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -O2" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi # Check whether --enable-flto was given. if test "${enable_flto+set}" = set; then : enableval=$enable_flto; fi if test "x$enable_flto" != "xno"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -flto" >&5 $as_echo_n "checking if $CC supports -flto... " >&6; } BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -flto" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if $CC $CFLAGS -o conftest conftest.c 2>&1 | $GREP -e "warning: no debug symbols in executable" -e "warning: object" >/dev/null; then CFLAGS="$BAKCFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest conftest.c conftest.o else CFLAGS="$BAKCFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # Check whether --enable-pie was given. if test "${enable_pie+set}" = set; then : enableval=$enable_pie; fi if test "x$enable_pie" = "xyes"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports PIE" >&5 $as_echo_n "checking if $CC supports PIE... " >&6; } BAKLDFLAGS="$LDFLAGS" BAKCFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS -pie" CFLAGS="$CFLAGS -fPIE" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then LDFLAGS="$BAKLDFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest conftest.c conftest.o else LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # Check whether --enable-relro_now was given. if test "${enable_relro_now+set}" = set; then : enableval=$enable_relro_now; fi if test "x$enable_relro_now" = "xyes"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wl,-z,relro,-z,now" >&5 $as_echo_n "checking if $CC supports -Wl,-z,relro,-z,now... " >&6; } BAKLDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then LDFLAGS="$BAKLDFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest conftest.c conftest.o else LDFLAGS="$BAKLDFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"format\" attribute" >&5 $as_echo_n "checking whether the C compiler (${CC-cc}) accepts the \"format\" attribute... " >&6; } if ${ac_cv_c_format_attribute+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_format_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void f (char *format, ...) __attribute__ ((format (printf, 1, 2))); void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2))); int main () { f ("%s", "str"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_format_attribute="yes" else ac_cv_c_format_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_format_attribute" >&5 $as_echo "$ac_cv_c_format_attribute" >&6; } if test $ac_cv_c_format_attribute = yes; then $as_echo "#define HAVE_ATTR_FORMAT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute" >&5 $as_echo_n "checking whether the C compiler (${CC-cc}) accepts the \"unused\" attribute... " >&6; } if ${ac_cv_c_unused_attribute+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_unused_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void f (char *u __attribute__((unused))); int main () { f ("x"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_unused_attribute="yes" else ac_cv_c_unused_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_unused_attribute" >&5 $as_echo "$ac_cv_c_unused_attribute" >&6; } if test $ac_cv_c_unused_attribute = yes; then $as_echo "#define HAVE_ATTR_UNUSED 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"noreturn\" attribute" >&5 $as_echo_n "checking whether the C compiler (${CC-cc}) accepts the \"noreturn\" attribute... " >&6; } if ${ac_cv_c_noreturn_attribute+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_noreturn_attribute=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include __attribute__((noreturn)) void f(int x) { printf("%d", x); } int main () { f(1); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_noreturn_attribute="yes" else ac_cv_c_noreturn_attribute="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_noreturn_attribute" >&5 $as_echo "$ac_cv_c_noreturn_attribute" >&6; } if test $ac_cv_c_noreturn_attribute = yes; then $as_echo "#define HAVE_ATTR_NORETURN 1" >>confdefs.h $as_echo "#define ATTR_NORETURN __attribute__((__noreturn__))" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if memcmp compares unsigned" >&5 $as_echo_n "checking if memcmp compares unsigned... " >&6; } if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compile no" >&5 $as_echo "cross-compile no" >&6; } $as_echo "#define MEMCMP_IS_BROKEN 1" >>confdefs.h case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main(void) { char a = 255, b = 0; if(memcmp(&a, &b, 1) < 0) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define MEMCMP_IS_BROKEN 1" >>confdefs.h case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ctime_r works with two arguments" >&5 $as_echo_n "checking whether ctime_r works with two arguments... " >&6; } if ${ac_cv_c_ctime_c+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_ctime_c=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include void testing (void) { time_t clock; char current_time[40]; ctime_r(&clock, current_time); } int main () { testing(); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_ctime_c="yes" else ac_cv_c_ctime_c="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_ctime_c" >&5 $as_echo "$ac_cv_c_ctime_c" >&6; } if test $ac_cv_c_ctime_c = no; then CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" fi # Checks for libraries. # Check for SSL, original taken from # http://www.gnu.org/software/ac-archive/htmldoc/check_ssl.html and # modified for NSD. # check for libevent # Check whether --with-libevent was given. if test "${with_libevent+set}" = set; then : withval=$with_libevent; else withval="yes" fi if test x_$withval = x_yes -o x_$withval != x_no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libevent" >&5 $as_echo_n "checking for libevent... " >&6; } if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr" fi for dir in $withval; do thedir="$dir" if test -f "$dir/include/event.h" -o -f "$dir/include/event2/event.h"; then found_libevent="yes" if test "$thedir" != "/usr"; then CPPFLAGS="$CPPFLAGS -I$thedir/include" fi break; fi done if test x_$found_libevent != x_yes; then if test -f "$dir/event.h" -a \( -f "$dir/libevent.la" -o -f "$dir/libev.la" \) ; then # libevent source directory { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in $thedir" >&5 $as_echo "found in $thedir" >&6; } CPPFLAGS="$CPPFLAGS -I$thedir -I$thedir/include" # remove evdns from linking ev_files_o=`ls $thedir/*.o | grep -v evdns\.o | grep -v bufferevent_openssl\.o` cp $ev_files_o . LDFLAGS="$ev_files_o $LDFLAGS -lm" else as_fn_error $? "Cannot find the libevent library. You can restart ./configure --with-libevent=no to use a builtin alternative." "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in $thedir" >&5 $as_echo "found in $thedir" >&6; } if test ! -f $thedir/lib/libevent.a -a ! -f $thedir/lib/libevent.so -a -d "$thedir/lib/event2"; then LDFLAGS="$LDFLAGS -L$thedir/lib/event2" if test "x$enable_rpath" = xyes; then if echo "$thedir/lib/event2" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib/event2" fi fi else if test "$thedir" != "/usr" -a "$thedir" != ""; then LDFLAGS="$LDFLAGS -L$thedir/lib" if test "x$enable_rpath" = xyes; then if echo "$thedir/lib" | grep "^/" >/dev/null; then RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib" fi fi fi fi fi # check for library used by libevent after 1.3c { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 $as_echo_n "checking for library containing clock_gettime... " >&6; } if ${ac_cv_search_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_clock_gettime+:} false; then : break fi done if ${ac_cv_search_clock_gettime+:} false; then : else ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 $as_echo "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # is the event.h header libev or libevent? for ac_header in event.h do : ac_fn_c_check_header_compile "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default " if test "x$ac_cv_header_event_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EVENT_H 1 _ACEOF fi done ac_fn_c_check_decl "$LINENO" "EV_VERSION_MAJOR" "ac_cv_have_decl_EV_VERSION_MAJOR" "$ac_includes_default #include " if test "x$ac_cv_have_decl_EV_VERSION_MAJOR" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing event_set" >&5 $as_echo_n "checking for library containing event_set... " >&6; } if ${ac_cv_search_event_set+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char event_set (); int main () { return event_set (); ; return 0; } _ACEOF for ac_lib in '' ev; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_event_set=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_event_set+:} false; then : break fi done if ${ac_cv_search_event_set+:} false; then : else ac_cv_search_event_set=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 $as_echo "$ac_cv_search_event_set" >&6; } ac_res=$ac_cv_search_event_set if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing event_set" >&5 $as_echo_n "checking for library containing event_set... " >&6; } if ${ac_cv_search_event_set+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char event_set (); int main () { return event_set (); ; return 0; } _ACEOF for ac_lib in '' event; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_event_set=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_event_set+:} false; then : break fi done if ${ac_cv_search_event_set+:} false; then : else ac_cv_search_event_set=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_set" >&5 $as_echo "$ac_cv_search_event_set" >&6; } ac_res=$ac_cv_search_event_set if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi for ac_func in event_base_free do : ac_fn_c_check_func "$LINENO" "event_base_free" "ac_cv_func_event_base_free" if test "x$ac_cv_func_event_base_free" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EVENT_BASE_FREE 1 _ACEOF fi done # only in libevent 1.2 and later for ac_func in event_base_once do : ac_fn_c_check_func "$LINENO" "event_base_once" "ac_cv_func_event_base_once" if test "x$ac_cv_func_event_base_once" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EVENT_BASE_ONCE 1 _ACEOF fi done # only in libevent 1.4.1 and later for ac_func in event_base_new do : ac_fn_c_check_func "$LINENO" "event_base_new" "ac_cv_func_event_base_new" if test "x$ac_cv_func_event_base_new" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EVENT_BASE_NEW 1 _ACEOF fi done # only in libevent 1.4.1 and later for ac_func in event_base_get_method do : ac_fn_c_check_func "$LINENO" "event_base_get_method" "ac_cv_func_event_base_get_method" if test "x$ac_cv_func_event_base_get_method" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EVENT_BASE_GET_METHOD 1 _ACEOF fi done # only in libevent 1.4.3 and later for ac_func in ev_loop do : ac_fn_c_check_func "$LINENO" "ev_loop" "ac_cv_func_ev_loop" if test "x$ac_cv_func_ev_loop" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EV_LOOP 1 _ACEOF fi done # only in libev. (tested on 3.51) for ac_func in ev_default_loop do : ac_fn_c_check_func "$LINENO" "ev_default_loop" "ac_cv_func_ev_default_loop" if test "x$ac_cv_func_ev_default_loop" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EV_DEFAULT_LOOP 1 _ACEOF fi done # only in libev. (tested on 4.00) else $as_echo "#define USE_MINI_EVENT 1" >>confdefs.h fi # Checks for header files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi for ac_header in time.h arpa/inet.h signal.h string.h strings.h fcntl.h limits.h netinet/in.h netinet/tcp.h stddef.h sys/param.h sys/socket.h sys/un.h syslog.h unistd.h sys/select.h stdarg.h stdint.h netdb.h sys/bitypes.h tcpd.h glob.h grp.h endian.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for double definition of struct va_list" >&5 $as_echo_n "checking for double definition of struct va_list... " >&6; } if ${ac_cv_c_va_list_def+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.c < #include int foo(void); EOF if test -z "`$CC -Werror -D_XOPEN_SOURCE=600 -c conftest.c 2>&1`"; then eval "ac_cv_c_va_list_def=no" else eval "ac_cv_c_va_list_def=yes" fi rm -f conftest* fi if test $ac_cv_c_va_list_def = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : cat >>confdefs.h <<_ACEOF #define HAVE_VA_LIST_DOUBLE_DEF /**/ _ACEOF else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strptime needs defines" >&5 $as_echo_n "checking whether strptime needs defines... " >&6; } if ${ac_cv_c_strptime_needs_defs+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.c < int testing (void) { struct tm t; const char *timestr="201201"; return strptime(timestr, "%Y%m", &t) != 0; } EOF if test -z "`$CC -Wall -Werror -c conftest.c 2>&1`"; then eval "ac_cv_c_strptime_needs_defs=no" else eval "ac_cv_c_strptime_needs_defs=yes" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_strptime_needs_defs" >&5 $as_echo "$ac_cv_c_strptime_needs_defs" >&6; } if test $ac_cv_c_strptime_needs_defs = yes; then cat >>confdefs.h <<_ACEOF #define STRPTIME_NEEDS_DEFINES 1 _ACEOF fi # check wether strptime also works { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_pton" >&5 $as_echo_n "checking for library containing inet_pton... " >&6; } if ${ac_cv_search_inet_pton+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_pton (); int main () { return inet_pton (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_inet_pton=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_inet_pton+:} false; then : break fi done if ${ac_cv_search_inet_pton+:} false; then : else ac_cv_search_inet_pton=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_pton" >&5 $as_echo "$ac_cv_search_inet_pton" >&6; } ac_res=$ac_cv_search_inet_pton if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if ${ac_cv_search_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_socket+:} false; then : break fi done if ${ac_cv_search_socket+:} false; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strptime works" >&5 $as_echo_n "checking whether strptime works... " >&6; } if test c${cross_compiling} = cno; then if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 600 #include int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : eval "ac_cv_c_strptime_works=yes" else eval "ac_cv_c_strptime_works=no" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else eval "ac_cv_c_strptime_works=maybe" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_strptime_works" >&5 $as_echo "$ac_cv_c_strptime_works" >&6; } if test $ac_cv_c_strptime_works = no; then case " $LIBOBJS " in *" strptime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strptime.$ac_objext" ;; esac else cat >>confdefs.h <<_ACEOF #define STRPTIME_WORKS 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if nonblocking sockets work" >&5 $as_echo_n "checking if nonblocking sockets work... " >&6; } if echo $target | grep mingw32 >/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (windows)" >&5 $as_echo "no (windows)" >&6; } $as_echo "#define NONBLOCKING_IS_BROKEN 1" >>confdefs.h else if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: crosscompile(yes)" >&5 $as_echo "crosscompile(yes)" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_TIME_H #include #endif int main(void) { int port; int sfd, cfd; int num = 10; int i, p; struct sockaddr_in a; /* test if select and nonblocking reads work well together */ /* open port. fork child to send 10 messages. select to read. then try to nonblocking read the 10 messages then, nonblocking read must give EAGAIN */ port = 12345 + (time(0)%32); sfd = socket(PF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket"); return 1; } memset(&a, 0, sizeof(a)); a.sin_family = AF_INET; a.sin_port = htons(port); a.sin_addr.s_addr = inet_addr("127.0.0.1"); if(bind(sfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("bind"); return 1; } if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) { perror("fcntl"); return 1; } cfd = socket(PF_INET, SOCK_DGRAM, 0); if(cfd == -1) { perror("client socket"); return 1; } a.sin_port = 0; if(bind(cfd, (struct sockaddr*)&a, sizeof(a)) < 0) { perror("client bind"); return 1; } a.sin_port = htons(port); /* no handler, causes exit in 10 seconds */ alarm(10); /* send and receive on the socket */ if((p=fork()) == 0) { for(i=0; i&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define NONBLOCKING_IS_BROKEN 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mkdir has one arg" >&5 $as_echo_n "checking whether mkdir has one arg... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif int main () { (void)mkdir("directory"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define MKDIR_HAS_ONE_ARG 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." else CPPFLAGS="-I." fi if test "$srcdir" != "."; then CPPFLAGS="$CPPFLAGS -I$srcdir" if test -f $srcdir/config.h; then as_fn_error $? "$srcdir/config.h is in the way, please remove it" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int8_t" >&5 $as_echo_n "checking for int8_t... " >&6; } if ${ac_cv_type_int8_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_int8_t=yes else ac_cv_type_int8_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int8_t" >&5 $as_echo "$ac_cv_type_int8_t" >&6; } if test $ac_cv_type_int8_t = no; then $as_echo "#define int8_t char" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int16_t" >&5 $as_echo_n "checking for int16_t... " >&6; } if ${ac_cv_type_int16_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_int16_t=yes else ac_cv_type_int16_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int16_t" >&5 $as_echo "$ac_cv_type_int16_t" >&6; } if test $ac_cv_type_int16_t = no; then $as_echo "#define int16_t short" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int32_t" >&5 $as_echo_n "checking for int32_t... " >&6; } if ${ac_cv_type_int32_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_int32_t=yes else ac_cv_type_int32_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int32_t" >&5 $as_echo "$ac_cv_type_int32_t" >&6; } if test $ac_cv_type_int32_t = no; then $as_echo "#define int32_t int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int64_t" >&5 $as_echo_n "checking for int64_t... " >&6; } if ${ac_cv_type_int64_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])int64_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_int64_t=yes else ac_cv_type_int64_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_int64_t" >&5 $as_echo "$ac_cv_type_int64_t" >&6; } if test $ac_cv_type_int64_t = no; then $as_echo "#define int64_t long long" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint8_t" >&5 $as_echo_n "checking for uint8_t... " >&6; } if ${ac_cv_type_uint8_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uint8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_uint8_t=yes else ac_cv_type_uint8_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint8_t" >&5 $as_echo "$ac_cv_type_uint8_t" >&6; } if test $ac_cv_type_uint8_t = no; then $as_echo "#define uint8_t unsigned char" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint16_t" >&5 $as_echo_n "checking for uint16_t... " >&6; } if ${ac_cv_type_uint16_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uint16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_uint16_t=yes else ac_cv_type_uint16_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5 $as_echo "$ac_cv_type_uint16_t" >&6; } if test $ac_cv_type_uint16_t = no; then $as_echo "#define uint16_t unsigned short" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5 $as_echo_n "checking for uint32_t... " >&6; } if ${ac_cv_type_uint32_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_uint32_t=yes else ac_cv_type_uint32_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5 $as_echo "$ac_cv_type_uint32_t" >&6; } if test $ac_cv_type_uint32_t = no; then $as_echo "#define uint32_t unsigned int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5 $as_echo_n "checking for uint64_t... " >&6; } if ${ac_cv_type_uint64_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uint64_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_uint64_t=yes else ac_cv_type_uint64_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5 $as_echo "$ac_cv_type_uint64_t" >&6; } if test $ac_cv_type_uint64_t = no; then $as_echo "#define uint64_t unsigned long long" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5 $as_echo_n "checking for socklen_t... " >&6; } if ${ac_cv_type_socklen_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])socklen_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_socklen_t=yes else ac_cv_type_socklen_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_socklen_t" >&5 $as_echo "$ac_cv_type_socklen_t" >&6; } if test $ac_cv_type_socklen_t = no; then $as_echo "#define socklen_t int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_atomic_t" >&5 $as_echo_n "checking for sig_atomic_t... " >&6; } if ${ac_cv_type_sig_atomic_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])sig_atomic_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_sig_atomic_t=yes else ac_cv_type_sig_atomic_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_sig_atomic_t" >&5 $as_echo "$ac_cv_type_sig_atomic_t" >&6; } if test $ac_cv_type_sig_atomic_t = no; then $as_echo "#define sig_atomic_t int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5 $as_echo_n "checking for ssize_t... " >&6; } if ${ac_cv_type_ssize_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_ssize_t=yes else ac_cv_type_ssize_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_ssize_t" >&5 $as_echo "$ac_cv_type_ssize_t" >&6; } if test $ac_cv_type_ssize_t = no; then $as_echo "#define ssize_t int" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suseconds_t" >&5 $as_echo_n "checking for suseconds_t... " >&6; } if ${ac_cv_type_suseconds_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])suseconds_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_suseconds_t=yes else ac_cv_type_suseconds_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_suseconds_t" >&5 $as_echo "$ac_cv_type_suseconds_t" >&6; } if test $ac_cv_type_suseconds_t = no; then $as_echo "#define suseconds_t time_t" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" " #if HAVE_SYS_TYPES_H # include #endif #if HAVE_NETINET_IN_H # include #endif " if test "x$ac_cv_type_in_addr_t" = xyes; then : else $as_echo "#define in_addr_t uint32_t" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "ss_family" "ac_cv_member_struct_sockaddr_storage_ss_family" "$ac_includes_default #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_storage_ss_family" = xyes; then : else ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "__ss_family" "ac_cv_member_struct_sockaddr_storage___ss_family" "$ac_includes_default #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_storage___ss_family" = xyes; then : $as_echo "#define ss_family __ss_family" >>confdefs.h fi fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" " $ac_includes_default #ifdef HAVE_SYS_UN_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1 _ACEOF fi # Checks for library functions. for ac_header in unistd.h do : ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNISTD_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 $as_echo_n "checking for working chown... " >&6; } if ${ac_cv_func_chown_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_chown_works=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main () { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_chown_works=yes else ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 $as_echo "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then $as_echo "#define HAVE_CHOWN 1" >>confdefs.h fi for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if ${ac_cv_type_signal+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 $as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if ${ac_cv_sys_largefile_source+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 $as_echo "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source _ACEOF ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void*" >&5 $as_echo_n "checking size of void*... " >&6; } if ${ac_cv_sizeof_voidp+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void*))" "ac_cv_sizeof_voidp" "$ac_includes_default"; then : else if test "$ac_cv_type_voidp" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void*) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_voidp=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_voidp" >&5 $as_echo "$ac_cv_sizeof_voidp" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_VOIDP $ac_cv_sizeof_voidp _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then : else if test "$ac_cv_type_off_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 $as_echo "$ac_cv_sizeof_off_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_OFF_T $ac_cv_sizeof_off_t _ACEOF for ac_func in arc4random arc4random_uniform do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in tzset alarm chroot dup2 endpwent gethostname memset memcpy pwrite socket strcasecmp strchr strdup strerror strncasecmp strtol writev getaddrinfo getnameinfo freeaddrinfo gai_strerror sigaction sigprocmask strptime strftime localtime_r setusercontext glob initgroups setresuid setreuid setresgid setregid getpwnam mmap ppoll clock_gettime accept4 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Check whether --enable-recvmmsg was given. if test "${enable_recvmmsg+set}" = set; then : enableval=$enable_recvmmsg; fi case "$enable_recvmmsg" in yes) ac_fn_c_check_func "$LINENO" "recvmmsg" "ac_cv_func_recvmmsg" if test "x$ac_cv_func_recvmmsg" = xyes; then : if test "$cross_compiling" = yes; then : $as_echo "#define HAVE_RECVMMSG 1" >>confdefs.h else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = recvmmsg(s, 0, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : $as_echo "#define HAVE_RECVMMSG 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi ac_fn_c_check_func "$LINENO" "sendmmsg" "ac_cv_func_sendmmsg" if test "x$ac_cv_func_sendmmsg" = xyes; then : if test "$cross_compiling" = yes; then : $as_echo "#define HAVE_SENDMMSG 1" >>confdefs.h else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main(void) { int s = socket(AF_INET, SOCK_DGRAM, 0); int r = sendmmsg(s, 0, 0, 0) == -1 && errno == ENOSYS; close(s); return r; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : $as_echo "#define HAVE_SENDMMSG 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi ;; no|*) ;; esac # check if setreuid en setregid fail, on MacOSX10.4(darwin8). if echo $target_os | grep darwin8 > /dev/null; then $as_echo "#define DARWIN_BROKEN_SETREUID 1" >>confdefs.h fi # # Checking for missing functions we can replace # ac_fn_c_check_func "$LINENO" "basename" "ac_cv_func_basename" if test "x$ac_cv_func_basename" = xyes; then : $as_echo "#define HAVE_BASENAME 1" >>confdefs.h else case " $LIBOBJS " in *" basename.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS basename.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton" if test "x$ac_cv_func_inet_aton" = xyes; then : $as_echo "#define HAVE_INET_ATON 1" >>confdefs.h else case " $LIBOBJS " in *" inet_aton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_aton.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton" if test "x$ac_cv_func_inet_pton" = xyes; then : $as_echo "#define HAVE_INET_PTON 1" >>confdefs.h else case " $LIBOBJS " in *" inet_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" if test "x$ac_cv_func_inet_ntop" = xyes; then : $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h else case " $LIBOBJS " in *" inet_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_ntop.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes; then : $as_echo "#define HAVE_SNPRINTF 1" >>confdefs.h else case " $LIBOBJS " in *" snprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS snprintf.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes; then : $as_echo "#define HAVE_STRLCAT 1" >>confdefs.h else case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes; then : $as_echo "#define HAVE_STRLCPY 1" >>confdefs.h else case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "strptime" "ac_cv_func_strptime" if test "x$ac_cv_func_strptime" = xyes; then : $as_echo "#define HAVE_STRPTIME 1" >>confdefs.h else case " $LIBOBJS " in *" strptime.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strptime.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "b64_pton" "ac_cv_func_b64_pton" if test "x$ac_cv_func_b64_pton" = xyes; then : $as_echo "#define HAVE_B64_PTON 1" >>confdefs.h else case " $LIBOBJS " in *" b64_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS b64_pton.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "b64_ntop" "ac_cv_func_b64_ntop" if test "x$ac_cv_func_b64_ntop" = xyes; then : $as_echo "#define HAVE_B64_NTOP 1" >>confdefs.h else case " $LIBOBJS " in *" b64_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS b64_ntop.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect" if test "x$ac_cv_func_pselect" = xyes; then : $as_echo "#define HAVE_PSELECT 1" >>confdefs.h else case " $LIBOBJS " in *" pselect.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS pselect.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" if test "x$ac_cv_func_memmove" = xyes; then : $as_echo "#define HAVE_MEMMOVE 1" >>confdefs.h else case " $LIBOBJS " in *" memmove.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memmove.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes; then : $as_echo "#define HAVE_REALLOCARRAY 1" >>confdefs.h else case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pselect prototype in sys/select.h" >&5 $as_echo_n "checking for pselect prototype in sys/select.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "[^a-zA-Z_]*pselect[^a-zA-Z_]" >/dev/null 2>&1; then : $as_echo "#define HAVE_PSELECT_PROTO 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ctime_r prototype in time.h" >&5 $as_echo_n "checking for ctime_r prototype in time.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "[^a-zA-Z_]*ctime_r[^a-zA-Z_]" >/dev/null 2>&1; then : $as_echo "#define HAVE_CTIME_R_PROTO 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f conftest* ac_fn_c_check_type "$LINENO" "struct timespec" "ac_cv_type_struct_timespec" " $ac_includes_default #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_TIME_H #include #endif " if test "x$ac_cv_type_struct_timespec" = xyes; then : $as_echo "#define HAVE_STRUCT_TIMESPEC 1" >>confdefs.h fi cat >>confdefs.h <<_ACEOF #define IDENTITY "unidentified server" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION PACKAGE_STRING _ACEOF cat >>confdefs.h <<_ACEOF #define TCP_BACKLOG 256 _ACEOF cat >>confdefs.h <<_ACEOF #define TCP_PORT "53" _ACEOF cat >>confdefs.h <<_ACEOF #define TCP_MAX_MESSAGE_LEN 65535 _ACEOF cat >>confdefs.h <<_ACEOF #define UDP_PORT "53" _ACEOF cat >>confdefs.h <<_ACEOF #define UDP_MAX_MESSAGE_LEN 512 _ACEOF cat >>confdefs.h <<_ACEOF #define EDNS_MAX_MESSAGE_LEN 4096 _ACEOF cat >>confdefs.h <<_ACEOF #define MAXSYSLOGMSGLEN 512 _ACEOF cat >>confdefs.h <<_ACEOF #define NSD_CONTROL_PORT 8952 _ACEOF cat >>confdefs.h <<_ACEOF #define NSD_CONTROL_VERSION 1 _ACEOF facility=LOG_DAEMON # Check whether --with-facility was given. if test "${with_facility+set}" = set; then : withval=$with_facility; facility=$withval fi cat >>confdefs.h <<_ACEOF #define FACILITY $facility _ACEOF tcp_timeout=120 # Check whether --with-tcp_timeout was given. if test "${with_tcp_timeout+set}" = set; then : withval=$with_tcp_timeout; tcp_timeout=$withval fi cat >>confdefs.h <<_ACEOF #define TCP_TIMEOUT $tcp_timeout _ACEOF # Check whether --enable-root-server was given. if test "${enable_root_server+set}" = set; then : enableval=$enable_root_server; fi case "$enable_root_server" in yes) cat >>confdefs.h <<_ACEOF #define ROOT_SERVER /**/ _ACEOF ;; no|*) ;; esac # Check whether --enable-ipv6 was given. if test "${enable_ipv6+set}" = set; then : enableval=$enable_ipv6; fi case "$enable_ipv6" in no) ;; yes|*) cat >>confdefs.h <<_ACEOF #define INET6 /**/ _ACEOF ;; esac # Check whether --enable-bind8-stats was given. if test "${enable_bind8_stats+set}" = set; then : enableval=$enable_bind8_stats; fi case "$enable_bind8_stats" in yes|'') cat >>confdefs.h <<_ACEOF #define BIND8_STATS /**/ _ACEOF ;; no|*) ;; esac # Check whether --enable-zone-stats was given. if test "${enable_zone_stats+set}" = set; then : enableval=$enable_zone_stats; fi case "$enable_zone_stats" in yes) cat >>confdefs.h <<_ACEOF #define USE_ZONE_STATS /**/ _ACEOF cat >>confdefs.h <<_ACEOF #define BIND8_STATS /**/ _ACEOF ;; no|''|*) ;; esac # Check whether --enable-checking was given. if test "${enable_checking+set}" = set; then : enableval=$enable_checking; fi case "$enable_checking" in yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -W" >&5 $as_echo_n "checking whether $CC supports -W... " >&6; } cache=`echo W | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(){}' >conftest.c if test -z "`$CC -W -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -W" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wall" >&5 $as_echo_n "checking whether $CC supports -Wall... " >&6; } cache=`echo Wall | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(){}' >conftest.c if test -z "`$CC -Wall -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -Wall" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wextra" >&5 $as_echo_n "checking whether $CC supports -Wextra... " >&6; } cache=`echo Wextra | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(){}' >conftest.c if test -z "`$CC -Wextra -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -Wextra" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 $as_echo_n "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } cache=`echo Wdeclaration-after-statement | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(){}' >conftest.c if test -z "`$CC -Wdeclaration-after-statement -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest* fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -Wdeclaration-after-statement" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi ;; no|*) $as_echo "#define NDEBUG /**/" >>confdefs.h ;; esac # Check whether --enable-memclean was given. if test "${enable_memclean+set}" = set; then : enableval=$enable_memclean; fi if test "$enable_memclean" = "yes"; then cat >>confdefs.h <<_ACEOF #define MEMCLEAN 1 _ACEOF fi # Check whether --enable-ratelimit was given. if test "${enable_ratelimit+set}" = set; then : enableval=$enable_ratelimit; fi case "$enable_ratelimit" in yes) cat >>confdefs.h <<_ACEOF #define RATELIMIT /**/ _ACEOF ratelimit="xx" ;; no|*) ratelimit="" ;; esac # Check whether --enable-ratelimit-default-is-off was given. if test "${enable_ratelimit_default_is_off+set}" = set; then : enableval=$enable_ratelimit_default_is_off; fi case "$enable_ratelimit_default_is_off" in yes) cat >>confdefs.h <<_ACEOF #define RATELIMIT_DEFAULT_OFF /**/ _ACEOF ratelimit_default="off" ;; no|*) ratelimit_default="on" ;; esac # we need SSL for TSIG (and maybe also for NSEC3). # Check whether --with-ssl was given. if test "${with_ssl+set}" = set; then : withval=$with_ssl; else withval="yes" fi if test x_$withval != x_no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL" >&5 $as_echo_n "checking for SSL... " >&6; } if test x_$withval = x_ -o x_$withval = x_yes; then withval="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/sfw /usr/local /usr" fi for dir in $withval; do ssldir="$dir" if test -f "$dir/include/openssl/ssl.h"; then found_ssl="yes"; cat >>confdefs.h <<_ACEOF #define HAVE_SSL /**/ _ACEOF if test x_$ssldir != x_/usr; then CPPFLAGS="$CPPFLAGS -I$ssldir/include"; fi break; fi done if test x_$found_ssl != x_yes; then as_fn_error $? "Cannot find the SSL libraries in $withval" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in $ssldir" >&5 $as_echo "found in $ssldir" >&6; } HAVE_SSL=yes if test x_$ssldir != x_/usr; then LDFLAGS="$LDFLAGS -L$ssldir/lib"; fi if test x_$ssldir = x_/usr/sfw; then LDFLAGS="$LDFLAGS -R$ssldir/lib"; fi fi fi if test x$HAVE_SSL = x"yes"; then # check if libssl needs libdl BAKLIBS="$LIBS" LIBS="-lssl $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libssl needs libdl" >&5 $as_echo_n "checking if libssl needs libdl... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_CTX_new (); int main () { return SSL_CTX_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } LIBS="$BAKLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } LIBS="$BAKLIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } if ${ac_cv_search_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF for ac_lib in '' dl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_dlopen+:} false; then : break fi done if ${ac_cv_search_dlopen+:} false; then : else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext # Check for -pthread BAKLIBS="$LIBS" LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int HMAC_Update(void); (void)HMAC_Update(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else BAKCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -pthread" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libcrypto needs -pthread" >&5 $as_echo_n "checking if libcrypto needs -pthread... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char HMAC_Update (); int main () { return HMAC_Update (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } CFLAGS="$BAKCFLAGS" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$BAKLIBS" if test -n "$ssldir"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for HMAC_Update in -lcrypto" >&5 $as_echo_n "checking for HMAC_Update in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_HMAC_Update+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char HMAC_Update (); int main () { return HMAC_Update (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_HMAC_Update=yes else ac_cv_lib_crypto_HMAC_Update=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_HMAC_Update" >&5 $as_echo "$ac_cv_lib_crypto_HMAC_Update" >&6; } if test "x$ac_cv_lib_crypto_HMAC_Update" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCRYPTO 1 _ACEOF LIBS="-lcrypto $LIBS" else as_fn_error $? "OpenSSL found in $ssldir, but version 0.9.7 or higher is required" "$LINENO" 5 fi fi SSL_LIBS="-lssl" for ac_header in openssl/ssl.h do : ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_ssl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENSSL_SSL_H 1 _ACEOF fi done for ac_header in openssl/err.h do : ac_fn_c_check_header_compile "$LINENO" "openssl/err.h" "ac_cv_header_openssl_err_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_err_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENSSL_ERR_H 1 _ACEOF fi done for ac_header in openssl/rand.h do : ac_fn_c_check_header_compile "$LINENO" "openssl/rand.h" "ac_cv_header_openssl_rand_h" "$ac_includes_default " if test "x$ac_cv_header_openssl_rand_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENSSL_RAND_H 1 _ACEOF fi done for ac_func in HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done BAKLIBS="$LIBS" LIBS="-lssl $LIBS" for ac_func in OPENSSL_init_ssl do : ac_fn_c_check_func "$LINENO" "OPENSSL_init_ssl" "ac_cv_func_OPENSSL_init_ssl" if test "x$ac_cv_func_OPENSSL_init_ssl" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENSSL_INIT_SSL 1 _ACEOF fi done LIBS="$BAKLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore remote-control is disabled" >&5 $as_echo "$as_me: WARNING: No SSL, therefore remote-control is disabled" >&2;} fi # Check whether --enable-nsec3 was given. if test "${enable_nsec3+set}" = set; then : enableval=$enable_nsec3; fi case "$enable_nsec3" in no) ;; yes) cat >>confdefs.h <<_ACEOF #define NSEC3 /**/ _ACEOF ;; *) if test x$HAVE_SSL = x"yes"; then cat >>confdefs.h <<_ACEOF #define NSEC3 /**/ _ACEOF else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore NSEC3 is disabled" >&5 $as_echo "$as_me: WARNING: No SSL, therefore NSEC3 is disabled" >&2;} fi ;; esac # Check whether --enable-minimal-responses was given. if test "${enable_minimal_responses+set}" = set; then : enableval=$enable_minimal_responses; fi case "$enable_minimal_responses" in no) ;; yes|*) cat >>confdefs.h <<_ACEOF #define MINIMAL_RESPONSES /**/ _ACEOF ;; esac # Check whether --enable-mmap was given. if test "${enable_mmap+set}" = set; then : enableval=$enable_mmap; fi case "$enable_mmap" in yes) for ac_header in sys/mman.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mman_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MMAN_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintptr_t" >&5 $as_echo_n "checking for uintptr_t... " >&6; } if ${ac_cv_type_uintptr_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if STDC_HEADERS #include #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* For Tru64 */ #ifdef HAVE_SYS_BITYPES_H #include #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uintptr_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_type_uintptr_t=yes else ac_cv_type_uintptr_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uintptr_t" >&5 $as_echo "$ac_cv_type_uintptr_t" >&6; } if test $ac_cv_type_uintptr_t = no; then $as_echo "#define uintptr_t void*" >>confdefs.h fi for ac_func in mmap munmap do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done cat >>confdefs.h <<_ACEOF #define USE_MMAP_ALLOC /**/ _ACEOF ;; no|*) ;; esac # Check whether --enable-radix-tree was given. if test "${enable_radix_tree+set}" = set; then : enableval=$enable_radix_tree; fi case "$enable_radix_tree" in no) ;; yes|*) cat >>confdefs.h <<_ACEOF #define USE_RADIX_TREE /**/ _ACEOF ;; esac # Check whether --enable-packed was given. if test "${enable_packed+set}" = set; then : enableval=$enable_packed; fi case "$enable_packed" in yes) cat >>confdefs.h <<_ACEOF #define PACKED_STRUCTS /**/ _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-address-of-packed-member" >&5 $as_echo_n "checking whether $CC supports -Wno-address-of-packed-member... " >&6; } cache=`echo Wno-address-of-packed-member | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -Wno-address-of-packed-member -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi rm -f conftest conftest.o conftest.c fi if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : CFLAGS="$CFLAGS -Wno-address-of-packed-member" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi ;; no|*) ;; esac # check for dnstap if requested # Check whether --enable-dnstap was given. if test "${enable_dnstap+set}" = set; then : enableval=$enable_dnstap; opt_dnstap=$enableval else opt_dnstap=no fi # Check whether --with-dnstap-socket-path was given. if test "${with_dnstap_socket_path+set}" = set; then : withval=$with_dnstap_socket_path; opt_dnstap_socket_path=$withval else opt_dnstap_socket_path="${localstatedir}/run/nsd-dnstap.sock" fi if test "x$opt_dnstap" != "xno"; then # Extract the first word of "protoc-c", so it can be a program name with args. set dummy protoc-c; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PROTOC_C+:} false; then : $as_echo_n "(cached) " >&6 else case $PROTOC_C in [\\/]* | ?:[\\/]*) ac_cv_path_PROTOC_C="$PROTOC_C" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PROTOC_C="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PROTOC_C=$ac_cv_path_PROTOC_C if test -n "$PROTOC_C"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROTOC_C" >&5 $as_echo "$PROTOC_C" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$PROTOC_C"; then as_fn_error $? "The protoc-c program was not found. Please install protobuf-c!" "$LINENO" 5 fi # Check whether --with-protobuf-c was given. if test "${with_protobuf_c+set}" = set; then : withval=$with_protobuf_c; # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f $withval/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I$withval/include/google" else CFLAGS="$CFLAGS -I$withval/include" fi LDFLAGS="$LDFLAGS -L$withval/lib" else # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f /usr/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/include/google" else if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/local/include/google" LDFLAGS="$LDFLAGS -L/usr/local/lib" fi fi fi # Check whether --with-libfstrm was given. if test "${with_libfstrm+set}" = set; then : withval=$with_libfstrm; CFLAGS="$CFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fstrm_iothr_init" >&5 $as_echo_n "checking for library containing fstrm_iothr_init... " >&6; } if ${ac_cv_search_fstrm_iothr_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char fstrm_iothr_init (); int main () { return fstrm_iothr_init (); ; return 0; } _ACEOF for ac_lib in '' fstrm; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_fstrm_iothr_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_fstrm_iothr_init+:} false; then : break fi done if ${ac_cv_search_fstrm_iothr_init+:} false; then : else ac_cv_search_fstrm_iothr_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fstrm_iothr_init" >&5 $as_echo "$ac_cv_search_fstrm_iothr_init" >&6; } ac_res=$ac_cv_search_fstrm_iothr_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "The fstrm library was not found. Please install fstrm!" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing protobuf_c_message_pack" >&5 $as_echo_n "checking for library containing protobuf_c_message_pack... " >&6; } if ${ac_cv_search_protobuf_c_message_pack+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char protobuf_c_message_pack (); int main () { return protobuf_c_message_pack (); ; return 0; } _ACEOF for ac_lib in '' protobuf-c; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_protobuf_c_message_pack=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_protobuf_c_message_pack+:} false; then : break fi done if ${ac_cv_search_protobuf_c_message_pack+:} false; then : else ac_cv_search_protobuf_c_message_pack=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_protobuf_c_message_pack" >&5 $as_echo "$ac_cv_search_protobuf_c_message_pack" >&6; } ac_res=$ac_cv_search_protobuf_c_message_pack if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "The protobuf-c library was not found. Please install protobuf-c!" "$LINENO" 5 fi $as_echo "#define USE_DNSTAP 1" >>confdefs.h ENABLE_DNSTAP=1 hdr_dnstap_socket_path="`echo $opt_dnstap_socket_path | sed -e 's/\\\\/\\\\\\\\/g'`" cat >>confdefs.h <<_ACEOF #define DNSTAP_SOCKET_PATH "$hdr_dnstap_socket_path" _ACEOF DNSTAP_SRC="dnstap/dnstap.c dnstap/dnstap.pb-c.c dnstap/dnstap_collector.c" DNSTAP_OBJ="dnstap.o dnstap_collector.o dnstap.pb-c.o" dnstap_config="dnstap/dnstap_config.h" else ENABLE_DNSTAP=0 fi # Include systemd.m4 - begin # macros for configuring systemd # Copyright 2015, Sami Kerola, CloudFlare. # BSD licensed. # Check whether --enable-systemd was given. if test "${enable_systemd+set}" = set; then : enableval=$enable_systemd; else enable_systemd=no fi have_systemd=no if test "x$enable_systemd" != xno; then : as_fn_error $? "systemd enabled but need pkg-config to configure for it, also, run aclocal before autoconf, or run autoreconf to include pkgconfig macros" "$LINENO" 5 fi # Include systemd.m4 - end if test $ac_cv_func_getaddrinfo = no; then case " $LIBOBJS " in *" fake-rfc2553.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS fake-rfc2553.$ac_objext" ;; esac fi # big fat warning if test "$enable_checking" = "yes"; then echo "************************************************" echo "* You have activated \"--enable-checking\" *" echo "* *" echo "* This will instruct NSD to be stricter *" echo "* when validating its input. This could lead *" echo "* to a reduced service level. *" echo "* *" echo "************************************************" fi ac_config_files="$ac_config_files Makefile $dnstap_config" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by NSD $as_me 4.1.26, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ NSD config.status 4.1.26 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "$dnstap_config") CONFIG_FILES="$CONFIG_FILES $dnstap_config" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nsd-4.1.26/xfrd.h0000664000175000017500000002702713202522614013147 0ustar wouterwouter/* * xfrd.h - XFR (transfer) Daemon header file. Coordinates SOA updates. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef XFRD_H #define XFRD_H #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "rbtree.h" #include "namedb.h" #include "options.h" #include "dns.h" #include "tsig.h" struct nsd; struct region; struct buffer; struct xfrd_tcp; struct xfrd_tcp_set; struct notify_zone; struct udb_ptr; typedef struct xfrd_state xfrd_state_type; typedef struct xfrd_zone xfrd_zone_type; typedef struct xfrd_soa xfrd_soa_type; /* * The global state for the xfrd daemon process. * The time_t times are epochs in secs since 1970, absolute times. */ struct xfrd_state { /* time when daemon was last started */ time_t xfrd_start_time; struct region* region; struct event_base* event_base; struct nsd* nsd; struct xfrd_tcp_set* tcp_set; /* packet buffer for udp packets */ struct buffer* packet; /* udp waiting list, double linked list */ struct xfrd_zone *udp_waiting_first, *udp_waiting_last; /* number of udp sockets (for sending queries) in use */ size_t udp_use_num; /* activated waiting list, double linked list */ struct xfrd_zone *activated_first; /* current time is cached */ uint8_t got_time; time_t current_time; /* counter for xfr file numbers */ uint64_t xfrfilenumber; /* the zonestat array size that we last saw and is safe to use */ unsigned zonestat_safe; /* size currently of the clear array */ size_t zonestat_clear_num; /* array of malloced entries with cumulative cleared stat values */ struct nsdst** zonestat_clear; /* timer for NSD reload */ struct timeval reload_timeout; struct event reload_handler; int reload_added; /* last reload must have caught all zone updates before this time */ time_t reload_cmd_last_sent; uint8_t can_send_reload; pid_t reload_pid; /* timeout for lost sigchild and reaping children */ struct event child_timer; int child_timer_added; /* timeout event for zonefiles_write events */ struct event write_timer; /* set to 1 if zones have received xfrs since the last write_timer */ int write_zonefile_needed; /* communication channel with server_main */ struct event ipc_handler; int ipc_handler_flags; struct xfrd_tcp *ipc_conn; struct buffer* ipc_pass; /* sending ipc to server_main */ uint8_t need_to_send_shutdown; uint8_t need_to_send_reload; uint8_t need_to_send_stats; uint8_t need_to_send_quit; uint8_t ipc_send_blocked; struct udb_ptr* last_task; /* xfrd shutdown flag */ uint8_t shutdown; /* tree of zones, by apex name, contains xfrd_zone_type*. Only secondary zones. */ rbtree_type *zones; /* tree of zones, by apex name, contains notify_zone*. All zones. */ rbtree_type *notify_zones; /* number of notify_zone active using UDP socket */ int notify_udp_num; /* first and last notify_zone* entries waiting for a UDP socket */ struct notify_zone *notify_waiting_first, *notify_waiting_last; }; /* * XFR daemon SOA information kept in network format. * This is in packet order. */ struct xfrd_soa { /* name of RR is zone apex dname */ uint16_t type; /* = TYPE_SOA */ uint16_t klass; /* = CLASS_IN */ uint32_t ttl; uint16_t rdata_count; /* = 7 */ /* format is 1 octet length, + wireformat dname. one more octet since parse_dname_wire_from_packet needs it. maximum size is allocated to avoid memory alloc/free. */ uint8_t prim_ns[MAXDOMAINLEN + 2]; uint8_t email[MAXDOMAINLEN + 2]; uint32_t serial; uint32_t refresh; uint32_t retry; uint32_t expire; uint32_t minimum; } ATTR_PACKED; /* * XFRD state for a single zone */ struct xfrd_zone { rbnode_type node; /* name of the zone */ const dname_type* apex; const char* apex_str; /* Three types of soas: * NSD: in use by running server * disk: stored on disk in db/diff file * notified: from notification, could be available on a master. * And the time the soa was acquired (start time for timeouts). * If the time==0, no SOA is available. */ xfrd_soa_type soa_nsd; time_t soa_nsd_acquired; xfrd_soa_type soa_disk; time_t soa_disk_acquired; xfrd_soa_type soa_notified; time_t soa_notified_acquired; enum xfrd_zone_state { xfrd_zone_ok, xfrd_zone_refreshing, xfrd_zone_expired } state; /* master to try to transfer from, number for persistence */ struct acl_options* master; int master_num; int next_master; /* -1 or set by notify where to try next */ /* round of xfrattempts, -1 is waiting for timeout */ int round_num; struct zone_options* zone_options; int fresh_xfr_timeout; /* handler for timeouts */ struct timeval timeout; struct event zone_handler; int zone_handler_flags; int event_added; /* tcp connection zone is using, or -1 */ int tcp_conn; /* zone is waiting for a tcp connection */ uint8_t tcp_waiting; /* next zone in waiting list */ xfrd_zone_type* tcp_waiting_next; xfrd_zone_type* tcp_waiting_prev; /* zone is in its tcp send queue */ uint8_t in_tcp_send; /* next zone in tcp send queue */ xfrd_zone_type* tcp_send_next; xfrd_zone_type* tcp_send_prev; /* zone is waiting for a udp connection (tcp is preferred) */ uint8_t udp_waiting; /* next zone in waiting list for UDP */ xfrd_zone_type* udp_waiting_next; xfrd_zone_type* udp_waiting_prev; /* zone has been activated to run now (after the other events * but before blocking in select again) */ uint8_t is_activated; xfrd_zone_type* activated_next; xfrd_zone_type* activated_prev; /* xfr message handling data */ /* query id */ uint16_t query_id; uint32_t msg_seq_nr; /* number of messages already handled */ uint32_t msg_old_serial, msg_new_serial; /* host byte order */ size_t msg_rr_count; uint8_t msg_is_ixfr; /* 1:IXFR detected. 2:middle IXFR SOA seen. */ tsig_record_type tsig; /* tsig state for IXFR/AXFR */ uint64_t xfrfilenumber; /* identifier for file to store xfr into, 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 */ xfrd_packet_drop, /* drop the connection, but not report bad */ xfrd_packet_more, /* more packets to follow on tcp */ xfrd_packet_notimpl, /* server responded with NOTIMPL or FORMATERR */ xfrd_packet_tcp, /* try tcp connection */ xfrd_packet_transfer, /* server responded with transfer*/ xfrd_packet_newlease /* no changes, soa OK */ }; /* Division of the (portably: 1024) max number of sockets that can be open. The sum of the below numbers should be below the user limit for sockets open, or you see errors in your logfile. And it should be below FD_SETSIZE, to be able to select() on replies. 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 128 /* max number of TCP AXFR/IXFR concurrent connections.*/ /* Each entry has 64Kb buffer preallocated.*/ #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 */ extern xfrd_state_type* xfrd; /* start xfrd, new start. Pass socket to server_main. */ void xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, pid_t nsd_pid); /* add new slave zone, dname(from zone_opt) and given options */ void xfrd_init_slave_zone(xfrd_state_type* xfrd, struct zone_options* zone_opt); /* delete slave zone */ void xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname); /* disable ixfr for a while for zone->master */ void xfrd_disable_ixfr(xfrd_zone_type* zone); /* get the current time epoch. Cached for speed. */ time_t xfrd_time(void); /* * Handle final received packet from network. * returns enum of packet discovery results */ enum xfrd_packet_result xfrd_handle_received_xfr_packet( xfrd_zone_type* zone, buffer_type* packet); /* set timer to specific value */ void xfrd_set_timer(xfrd_zone_type* zone, time_t t); /* set refresh timer of zone to refresh at time now */ void xfrd_set_refresh_now(xfrd_zone_type* zone); /* unset the timer - no more timeouts, for when zone is queued */ void xfrd_unset_timer(xfrd_zone_type* zone); /* remove the 'refresh now', remove it from the activated list */ void xfrd_deactivate_zone(xfrd_zone_type* z); /* * Make a new request to next master server. * uses next_master if set (and a fresh set of rounds). * otherwised, starts new round of requests if none started already. * starts next round of requests if at last master. * if too many rounds of requests, sets timer for next retry. */ void xfrd_make_request(xfrd_zone_type* zone); /* * send packet via udp (returns UDP fd source socket) to acl addr. * returns -1 on failure. */ int xfrd_send_udp(struct acl_options* acl, buffer_type* packet, struct acl_options* ifc); /* * read from udp port packet into buffer, returns 0 on failure */ int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src, socklen_t* srclen); /* * Release udp socket that a zone is using */ void xfrd_udp_release(xfrd_zone_type* zone); /* * Get a static buffer for temporary use (to build a packet). */ struct buffer* xfrd_get_temp_buffer(void); /* * TSIG sign outgoing request. Call if acl has a key. */ void xfrd_tsig_sign_request(buffer_type* packet, struct tsig_record* tsig, struct acl_options* acl); /* handle incoming soa information (NSD is running it, time acquired=guess). Pass soa=NULL,acquired=now if NSD has nothing loaded for the zone (i.e. zonefile was deleted). */ void xfrd_handle_incoming_soa(xfrd_zone_type* zone, xfrd_soa_type* soa, time_t acquired); /* handle a packet passed along ipc route. acl is the one that accepted the packet. The packet is the network blob received. acl_xfr is provide-xfr acl matching notify sender or -1 */ void xfrd_handle_passed_packet(buffer_type* packet, int acl_num, int acl_xfr); /* try to reopen the logfile. */ void xfrd_reopen_logfile(void); /* free namedb for xfrd usage */ void xfrd_free_namedb(struct nsd* nsd); /* copy SOA info from rr to soa struct. */ void xfrd_copy_soa(xfrd_soa_type* soa, rr_type* rr); /* check for failed updates - it is assumed that now the reload has finished, and all zone SOAs have been sent. */ void xfrd_check_failed_updates(void); /* * Prepare zones for a reload, this sets the times on the zones to be * before the current time, so the reload happens after. */ void xfrd_prepare_zones_for_reload(void); /* Bind a local interface to a socket descriptor, return 1 on success */ int xfrd_bind_local_interface(int sockd, struct acl_options* ifc, struct acl_options* acl, int tcp); /* process results and soa info from reload */ void xfrd_process_task_result(xfrd_state_type* xfrd, struct udb_base* taskudb); /* set to reload right away (for user controlled reload events) */ void xfrd_set_reload_now(xfrd_state_type* xfrd); /* send expiry notifications to nsd */ void xfrd_send_expire_notification(xfrd_zone_type* zone); /* handle incoming notify (soa or NULL) and start zone xfr if necessary */ void xfrd_handle_notify_and_start_xfr(xfrd_zone_type* zone, xfrd_soa_type* soa); /* handle zone timeout, event */ void xfrd_handle_zone(int fd, short event, void* arg); const char* xfrd_pretty_time(time_t v); #endif /* XFRD_H */ nsd-4.1.26/install-sh0000775000175000017500000001273607612733365014057 0ustar wouterwouter#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 nsd-4.1.26/configlexer.lex0000664000175000017500000003171213376741366015071 0ustar wouterwouter%{ /* * configlexer.lex - lexical analyzer for NSD config file * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif #include "config.h" #include #include #include #include #ifdef HAVE_GLOB_H # include #endif #include "options.h" #include "configyyrename.h" #include "configparser.h" void c_error(const char *message); #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif struct inc_state { char* filename; int line; YY_BUFFER_STATE buffer; struct inc_state* next; }; static struct inc_state* config_include_stack = NULL; static int inc_depth = 0; static int inc_prev = 0; static int num_args = 0; void init_cfg_parse(void) { config_include_stack = NULL; inc_depth = 0; inc_prev = 0; num_args = 0; } static void config_start_include(const char* filename) { FILE *input; struct inc_state* s; char* nm; if(inc_depth++ > 10000000) { c_error_msg("too many include files"); return; } if(strlen(filename) == 0) { c_error_msg("empty include file name"); return; } s = (struct inc_state*)malloc(sizeof(*s)); if(!s) { c_error_msg("include %s: malloc failure", filename); return; } nm = strdup(filename); if(!nm) { c_error_msg("include %s: strdup failure", filename); free(s); return; } input = fopen(filename, "r"); if(!input) { c_error_msg("cannot open include file '%s': %s", filename, strerror(errno)); free(s); free(nm); return; } LEXOUT(("switch_to_include_file(%s) ", filename)); s->filename = cfg_parser->filename; s->line = cfg_parser->line; s->buffer = YY_CURRENT_BUFFER; s->next = config_include_stack; config_include_stack = s; cfg_parser->filename = nm; cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); } static void config_start_include_glob(const char* filename) { /* check for wildcards */ #ifdef HAVE_GLOB glob_t g; size_t i; int r, flags; #endif /* HAVE_GLOB */ if (cfg_parser->chroot) { int l = strlen(cfg_parser->chroot); /* chroot has trailing slash */ if (strncmp(cfg_parser->chroot, filename, l) != 0) { c_error_msg("include file '%s' is not relative to chroot '%s'", filename, cfg_parser->chroot); return; } filename += l - 1; /* strip chroot without trailing slash */ } #ifdef HAVE_GLOB if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') && !strchr(filename, '{') && !strchr(filename, '~'))) { flags = 0 #ifdef GLOB_ERR | GLOB_ERR #endif /* do not set GLOB_NOSORT so the results are sorted and in a predictable order. */ #ifdef GLOB_BRACE | GLOB_BRACE #endif #ifdef GLOB_TILDE | GLOB_TILDE #endif ; memset(&g, 0, sizeof(g)); r = glob(filename, flags, NULL, &g); if(r) { /* some error */ globfree(&g); if(r == GLOB_NOMATCH) return; /* no matches for pattern */ config_start_include(filename); /* let original deal with it */ return; } /* process files found, if any */ for(i=0; i<(size_t)g.gl_pathc; i++) { config_start_include(g.gl_pathv[i]); } globfree(&g); return; } #endif /* HAVE_GLOB */ config_start_include(filename); } static void config_end_include(void) { struct inc_state* s = config_include_stack; --inc_depth; if(!s) return; free(cfg_parser->filename); cfg_parser->filename = s->filename; cfg_parser->line = s->line; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(s->buffer); config_include_stack = s->next; free(s); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif %} %option noinput %option nounput %{ #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif %} SPACE [ \t] LETTER [a-zA-Z] UNQUOTEDLETTER [^\"\n\r \t\\]|\\. NEWLINE [\r\n] COMMENT \# COLON \: ANY [^\"\n\r\\]|\\. %x quotedstring include include_quoted %% {SPACE}* { LEXOUT(("SP ")); /* ignore */ } {SPACE}*{COMMENT}.* { LEXOUT(("comment(%s) ", yytext)); /* ignore */ } server{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} name{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;} ip-address{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} ip-transparent{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;} ip-freebind{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;} debug-mode{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;} use-systemd{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;} hide-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;} ip4-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;} ip6-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;} do-ip4{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;} do-ip6{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;} database{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;} identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;} version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;} nsid{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NSID;} logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;} server-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;} tcp-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;} tcp-query-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;} tcp-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;} tcp-mss{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;} outgoing-tcp-mss{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;} ipv4-edns-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;} ipv6-edns-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;} pidfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;} port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;} reuseport{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;} statistics{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;} chroot{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;} username{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;} zonesdir{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;} zonelistfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;} difffile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;} xfrdfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;} xfrdir{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;} xfrd-reload-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;} verbosity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;} zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;} zonefile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;} zonestats{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;} allow-notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;} size-limit-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;} request-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;} notify{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;} notify-retry{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;} provide-xfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;} outgoing-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;} allow-axfr-fallback{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;} key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_KEY;} algorithm{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;} secret{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;} pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;} include-pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDEPATTERN;} remote-control{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;} control-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;} control-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;} control-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;} server-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;} server-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;} control-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;} control-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;} AXFR { LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;} UDP { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} rrl-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} rrl-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;} rrl-slip{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;} rrl-ipv4-prefix-length{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;} rrl-ipv6-prefix-length{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;} rrl-whitelist-ratelimit{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;} rrl-whitelist{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;} zonefiles-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;} zonefiles-write{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;} dnstap{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;} dnstap-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;} dnstap-socket-path{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; } dnstap-send-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; } dnstap-send-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; } dnstap-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; } dnstap-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; } dnstap-log-auth-query-messages{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; } dnstap-log-auth-response-messages{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; } log-time-ascii{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;} round-robin{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;} minimal-responses{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;} refuse-any{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;} max-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;} min-refresh-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;} max-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;} min-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;} multi-master-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;} {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} /* Quoted strings. Strip leading and ending quotes */ \" { BEGIN(quotedstring); LEXOUT(("QS ")); } <> { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("STR(%s) ", yytext)); yymore(); } \n { cfg_parser->line++; yymore(); } \" { LEXOUT(("QE ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; yylval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } /* include: directive */ include{COLON} { LEXOUT(("v(%s) ", yytext)); BEGIN(include); } <> { yyerror("EOF inside include directive"); BEGIN(INITIAL); } {SPACE}* { LEXOUT(("ISP ")); /* ignore */ } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} \" { LEXOUT(("IQS ")); BEGIN(include_quoted); } {UNQUOTEDLETTER}* { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext); BEGIN(INITIAL); } <> { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } {ANY}* { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } {NEWLINE} { cfg_parser->line++; yymore(); } \" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; config_start_include_glob(yytext); BEGIN(INITIAL); } <> { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (!config_include_stack) { yyterminate(); } else { fclose(yyin); config_end_include(); } } {UNQUOTEDLETTER}* { LEXOUT(("unquotedstr(%s) ", yytext)); yylval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } %% nsd-4.1.26/nsd.c0000664000175000017500000007366513355422740013004 0ustar wouterwouter/* * nsd.c -- nsd(8) * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_GRP_H #include #endif /* HAVE_GRP_H */ #ifdef HAVE_SETUSERCONTEXT #include #endif /* HAVE_SETUSERCONTEXT */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nsd.h" #include "options.h" #include "tsig.h" #include "remote.h" #include "xfrd-disk.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif /* The server handler... */ struct nsd nsd; static char hostname[MAXHOSTNAMELEN]; extern config_parser_state_type* cfg_parser; static void version(void) ATTR_NORETURN; /* * Print the help text. * */ static void usage (void) { fprintf(stderr, "Usage: nsd [OPTION]...\n"); fprintf(stderr, "Name Server Daemon.\n\n"); fprintf(stderr, "Supported options:\n" " -4 Only listen to IPv4 connections.\n" " -6 Only listen to IPv6 connections.\n" " -a ip-address[@port] Listen to the specified incoming IP address (and port)\n" " May be specified multiple times).\n" " -c configfile Read specified configfile instead of %s.\n" " -d do not fork as a daemon process.\n" #ifndef NDEBUG " -F facilities Specify the debug facilities.\n" #endif /* NDEBUG */ " -f database Specify the database to load.\n" " -h Print this help information.\n" , CONFIGFILE); fprintf(stderr, " -i identity Specify the identity when queried for id.server CHAOS TXT.\n" " -I nsid Specify the NSID. This must be a hex string.\n" #ifndef NDEBUG " -L level Specify the debug level.\n" #endif /* NDEBUG */ " -l filename Specify the log file.\n" " -N server-count The number of servers to start.\n" " -n tcp-count The maximum number of TCP connections per server.\n" " -P pidfile Specify the PID file to write.\n" " -p port Specify the port to listen to.\n" " -s seconds Dump statistics every SECONDS seconds.\n" " -t chrootdir Change root to specified directory on startup.\n" ); fprintf(stderr, " -u user Change effective uid to the specified user.\n" " -V level Specify verbosity level.\n" " -v Print version information.\n" ); fprintf(stderr, "Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); } /* * Print the version exit. * */ static void version(void) { fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); fprintf(stderr, "Written by NLnet Labs.\n\n"); fprintf(stderr, "Copyright (C) 2001-2006 NLnet Labs. This is free software.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n" "FOR A PARTICULAR PURPOSE.\n"); exit(0); } void get_ip_port_frm_str(const char* arg, const char** hostname, const char** port) { /* parse src[@port] option */ char* delim = NULL; if (arg) { delim = strchr(arg, '@'); } if (delim) { *delim = '\0'; *port = delim+1; } *hostname = arg; } /* append interface to interface array (names, udp, tcp) */ void add_interface(char*** nodes, struct nsd* nsd, char* ip) { /* realloc the arrays */ if(nsd->ifs == 0) { *nodes = xalloc_zero(sizeof(*nodes)); nsd->udp = xalloc_zero(sizeof(*nsd->udp)); nsd->tcp = xalloc_zero(sizeof(*nsd->udp)); } else { region_remove_cleanup(nsd->region, free, *nodes); region_remove_cleanup(nsd->region, free, nsd->udp); region_remove_cleanup(nsd->region, free, nsd->tcp); *nodes = xrealloc(*nodes, (nsd->ifs+1)*sizeof(*nodes)); nsd->udp = xrealloc(nsd->udp, (nsd->ifs+1)*sizeof(*nsd->udp)); nsd->tcp = xrealloc(nsd->tcp, (nsd->ifs+1)*sizeof(*nsd->udp)); (*nodes)[nsd->ifs] = NULL; memset(&nsd->udp[nsd->ifs], 0, sizeof(*nsd->udp)); memset(&nsd->tcp[nsd->ifs], 0, sizeof(*nsd->tcp)); } region_add_cleanup(nsd->region, free, *nodes); region_add_cleanup(nsd->region, free, nsd->udp); region_add_cleanup(nsd->region, free, nsd->tcp); /* add it */ (*nodes)[nsd->ifs] = ip; ++nsd->ifs; } /* * Fetch the nsd parent process id from the nsd pidfile * */ pid_t readpid(const char *file) { int fd; pid_t pid; char pidbuf[16]; char *t; int l; if ((fd = open(file, O_RDONLY)) == -1) { return -1; } if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { close(fd); return -1; } close(fd); /* Empty pidfile means no pidfile... */ if (l == 0) { errno = ENOENT; return -1; } pid = (pid_t) strtol(pidbuf, &t, 10); if (*t && *t != '\n') { return -1; } return pid; } /* * Store the nsd parent process id in the nsd pidfile * */ int writepid(struct nsd *nsd) { FILE * fd; char pidbuf[32]; snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) nsd->pid); if ((fd = fopen(nsd->pidfile, "w")) == NULL ) { log_msg(LOG_ERR, "cannot open pidfile %s: %s", nsd->pidfile, strerror(errno)); return -1; } if (!write_data(fd, pidbuf, strlen(pidbuf))) { log_msg(LOG_ERR, "cannot write pidfile %s: %s", nsd->pidfile, strerror(errno)); fclose(fd); return -1; } fclose(fd); if (chown(nsd->pidfile, nsd->uid, nsd->gid) == -1) { log_msg(LOG_ERR, "cannot chown %u.%u %s: %s", (unsigned) nsd->uid, (unsigned) nsd->gid, nsd->pidfile, strerror(errno)); return -1; } return 0; } void unlinkpid(const char* file) { int fd = -1; if (file) { /* truncate pidfile */ fd = open(file, O_WRONLY | O_TRUNC, 0644); if (fd == -1) { /* Truncate the pid file. */ log_msg(LOG_ERR, "can not truncate the pid file %s: %s", file, strerror(errno)); } else close(fd); /* unlink pidfile */ if (unlink(file) == -1) log_msg(LOG_WARNING, "failed to unlink pidfile %s: %s", file, strerror(errno)); } } /* * Incoming signals, set appropriate actions. * */ void sig_handler(int sig) { /* To avoid race cond. We really don't want to use log_msg() in this handler */ /* Are we a child server? */ if (nsd.server_kind != NSD_SERVER_MAIN) { switch (sig) { case SIGCHLD: nsd.signal_hint_child = 1; break; case SIGALRM: break; case SIGINT: case SIGTERM: nsd.signal_hint_quit = 1; break; case SIGILL: case SIGUSR1: /* Dump stats on SIGUSR1. */ nsd.signal_hint_statsusr = 1; break; default: break; } return; } /* We are the main process */ switch (sig) { case SIGCHLD: nsd.signal_hint_child = 1; return; case SIGHUP: nsd.signal_hint_reload_hup = 1; return; case SIGALRM: nsd.signal_hint_stats = 1; break; case SIGILL: /* * For backwards compatibility with BIND 8 and older * versions of NSD. */ nsd.signal_hint_statsusr = 1; break; case SIGUSR1: /* Dump statistics. */ nsd.signal_hint_statsusr = 1; break; case SIGINT: case SIGTERM: default: nsd.signal_hint_shutdown = 1; break; } } /* * Statistic output... * */ #ifdef BIND8_STATS void bind8_stats (struct nsd *nsd) { char buf[MAXSYSLOGMSGLEN]; char *msg, *t; int i, len; /* Current time... */ time_t now; if(!nsd->st.period) return; time(&now); /* NSTATS */ t = msg = buf + snprintf(buf, MAXSYSLOGMSGLEN, "NSTATS %lld %lu", (long long) now, (unsigned long) nsd->st.boot); for (i = 0; i <= 255; i++) { /* How much space left? */ if ((len = buf + MAXSYSLOGMSGLEN - t) < 32) { log_msg(LOG_INFO, "%s", buf); t = msg; len = buf + MAXSYSLOGMSGLEN - t; } if (nsd->st.qtype[i] != 0) { t += snprintf(t, len, " %s=%lu", rrtype_to_string(i), nsd->st.qtype[i]); } } if (t > msg) log_msg(LOG_INFO, "%s", buf); /* XSTATS */ /* Only print it if we're in the main daemon or have anything to report... */ if (nsd->server_kind == NSD_SERVER_MAIN || nsd->st.dropped || nsd->st.raxfr || (nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped) || nsd->st.txerr || nsd->st.opcode[OPCODE_QUERY] || nsd->st.opcode[OPCODE_IQUERY] || nsd->st.wrongzone || nsd->st.ctcp + nsd->st.ctcp6 || nsd->st.rcode[RCODE_SERVFAIL] || nsd->st.rcode[RCODE_FORMAT] || nsd->st.nona || nsd->st.rcode[RCODE_NXDOMAIN] || nsd->st.opcode[OPCODE_UPDATE]) { log_msg(LOG_INFO, "XSTATS %lld %lu" " RR=%lu RNXD=%lu RFwdR=%lu RDupR=%lu RFail=%lu RFErr=%lu RErr=%lu RAXFR=%lu" " RLame=%lu ROpts=%lu SSysQ=%lu SAns=%lu SFwdQ=%lu SDupQ=%lu SErr=%lu RQ=%lu" " RIQ=%lu RFwdQ=%lu RDupQ=%lu RTCP=%lu SFwdR=%lu SFail=%lu SFErr=%lu SNaAns=%lu" " SNXD=%lu RUQ=%lu RURQ=%lu RUXFR=%lu RUUpd=%lu", (long long) now, (unsigned long) nsd->st.boot, nsd->st.dropped, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, nsd->st.raxfr, (unsigned long)0, (unsigned long)0, (unsigned long)0, nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped, (unsigned long)0, (unsigned long)0, nsd->st.txerr, nsd->st.opcode[OPCODE_QUERY], nsd->st.opcode[OPCODE_IQUERY], nsd->st.wrongzone, (unsigned long)0, nsd->st.ctcp + nsd->st.ctcp6, (unsigned long)0, nsd->st.rcode[RCODE_SERVFAIL], nsd->st.rcode[RCODE_FORMAT], nsd->st.nona, nsd->st.rcode[RCODE_NXDOMAIN], (unsigned long)0, (unsigned long)0, (unsigned long)0, nsd->st.opcode[OPCODE_UPDATE]); } } #endif /* BIND8_STATS */ extern char *optarg; extern int optind; int main(int argc, char *argv[]) { /* Scratch variables... */ int c; pid_t oldpid; size_t i; struct sigaction action; #ifdef HAVE_GETPWNAM struct passwd *pwd = NULL; #endif /* HAVE_GETPWNAM */ struct addrinfo hints[2]; int hints_in_use = 1; char** nodes = NULL; /* array of address strings, size nsd.ifs */ const char *udp_port = 0; const char *tcp_port = 0; const char *configfile = CONFIGFILE; char* argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0]; log_init(argv0); /* Initialize the server handler... */ memset(&nsd, 0, sizeof(struct nsd)); nsd.region = region_create(xalloc, free); nsd.dbfile = 0; nsd.pidfile = 0; nsd.server_kind = NSD_SERVER_MAIN; memset(&hints, 0, sizeof(*hints)*2); hints[0].ai_family = DEFAULT_AI_FAMILY; hints[0].ai_flags = AI_PASSIVE; hints[1].ai_family = DEFAULT_AI_FAMILY; hints[1].ai_flags = AI_PASSIVE; nsd.identity = 0; nsd.version = VERSION; nsd.username = 0; nsd.chrootdir = 0; nsd.nsid = NULL; nsd.nsid_len = 0; nsd.child_count = 0; nsd.maximum_tcp_count = 0; nsd.current_tcp_count = 0; nsd.grab_ip6_optional = 0; nsd.file_rotation_ok = 0; /* Set up our default identity to gethostname(2) */ if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { nsd.identity = hostname; } else { log_msg(LOG_ERR, "failed to get the host name: %s - using default identity", strerror(errno)); nsd.identity = IDENTITY; } /* Parse the command line... */ while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:s:u:t:X:V:v" #ifndef NDEBUG /* only when configured with --enable-checking */ "F:L:" #endif /* NDEBUG */ )) != -1) { switch (c) { case '4': hints[0].ai_family = AF_INET; break; case '6': #ifdef INET6 hints[0].ai_family = AF_INET6; #else /* !INET6 */ error("IPv6 support not enabled."); #endif /* INET6 */ break; case 'a': add_interface(&nodes, &nsd, optarg); break; case 'c': configfile = optarg; break; case 'd': nsd.debug = 1; break; case 'f': nsd.dbfile = optarg; break; case 'h': usage(); exit(0); case 'i': nsd.identity = optarg; break; case 'I': if (nsd.nsid_len != 0) { /* can only be given once */ break; } if (strncasecmp(optarg, "ascii_", 6) == 0) { nsd.nsid = xalloc(strlen(optarg+6)); nsd.nsid_len = strlen(optarg+6); memmove(nsd.nsid, optarg+6, nsd.nsid_len); } else { if (strlen(optarg) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(optarg) / 2); nsd.nsid_len = strlen(optarg) / 2; if (hex_pton(optarg, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", optarg); } } break; case 'l': nsd.log_filename = optarg; break; case 'N': i = atoi(optarg); if (i <= 0) { error("number of child servers must be greater than zero."); } else { nsd.child_count = i; } break; case 'n': i = atoi(optarg); if (i <= 0) { error("number of concurrent TCP connections must greater than zero."); } else { nsd.maximum_tcp_count = i; } break; case 'P': nsd.pidfile = optarg; break; case 'p': if (atoi(optarg) == 0) { error("port argument must be numeric."); } tcp_port = optarg; udp_port = optarg; break; case 's': #ifdef BIND8_STATS nsd.st.period = atoi(optarg); #else /* !BIND8_STATS */ error("BIND 8 statistics not enabled."); #endif /* BIND8_STATS */ break; case 't': #ifdef HAVE_CHROOT nsd.chrootdir = optarg; #else /* !HAVE_CHROOT */ error("chroot not supported on this platform."); #endif /* HAVE_CHROOT */ break; case 'u': nsd.username = optarg; break; case 'V': verbosity = atoi(optarg); break; case 'v': version(); /* version exits */ break; #ifndef NDEBUG case 'F': sscanf(optarg, "%x", &nsd_debug_facilities); break; case 'L': sscanf(optarg, "%d", &nsd_debug_level); break; #endif /* NDEBUG */ case '?': default: usage(); exit(1); } } argc -= optind; /* argv += optind; */ /* Commandline parse error */ if (argc != 0) { usage(); exit(1); } if (strlen(nsd.identity) > UCHAR_MAX) { error("server identity too long (%u characters)", (unsigned) strlen(nsd.identity)); } if(!tsig_init(nsd.region)) error("init tsig failed"); /* Read options */ nsd.options = nsd_options_create(region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { error("could not read zonelist file %s\n", nsd.options->zonelistfile); } if(nsd.options->do_ip4 && !nsd.options->do_ip6) { hints[0].ai_family = AF_INET; } #ifdef INET6 if(nsd.options->do_ip6 && !nsd.options->do_ip4) { hints[0].ai_family = AF_INET6; } #endif /* INET6 */ if(nsd.options->ip_addresses) { ip_address_option_type* ip = nsd.options->ip_addresses; while(ip) { add_interface(&nodes, &nsd, ip->address); ip = ip->next; } } if (verbosity == 0) verbosity = nsd.options->verbosity; #ifndef NDEBUG if (nsd_debug_level > 0 && verbosity == 0) verbosity = nsd_debug_level; #endif /* NDEBUG */ if(nsd.options->debug_mode) nsd.debug=1; if(!nsd.dbfile) { if(nsd.options->database) nsd.dbfile = nsd.options->database; else nsd.dbfile = DBFILE; } if(!nsd.pidfile) { if(nsd.options->pidfile) nsd.pidfile = nsd.options->pidfile; else nsd.pidfile = PIDFILE; } if(strcmp(nsd.identity, hostname)==0 || strcmp(nsd.identity,IDENTITY)==0) { if(nsd.options->identity) nsd.identity = nsd.options->identity; } if(nsd.options->version) { nsd.version = nsd.options->version; } if (nsd.options->logfile && !nsd.log_filename) { nsd.log_filename = nsd.options->logfile; } if(nsd.child_count == 0) { nsd.child_count = nsd.options->server_count; } #ifdef SO_REUSEPORT if(nsd.options->reuseport && nsd.child_count > 1) { nsd.reuseport = nsd.child_count; } #endif /* SO_REUSEPORT */ if(nsd.maximum_tcp_count == 0) { nsd.maximum_tcp_count = nsd.options->tcp_count; } nsd.tcp_timeout = nsd.options->tcp_timeout; nsd.tcp_query_count = nsd.options->tcp_query_count; nsd.tcp_mss = nsd.options->tcp_mss; nsd.outgoing_tcp_mss = nsd.options->outgoing_tcp_mss; nsd.ipv4_edns_size = nsd.options->ipv4_edns_size; nsd.ipv6_edns_size = nsd.options->ipv6_edns_size; if(udp_port == 0) { if(nsd.options->port != 0) { udp_port = nsd.options->port; tcp_port = nsd.options->port; } else { udp_port = UDP_PORT; tcp_port = TCP_PORT; } } #ifdef BIND8_STATS if(nsd.st.period == 0) { nsd.st.period = nsd.options->statistics; } #endif /* BIND8_STATS */ #ifdef HAVE_CHROOT if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; #ifdef CHROOTDIR /* if still no chrootdir, fallback to default */ if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; #endif /* CHROOTDIR */ #endif /* HAVE_CHROOT */ if(nsd.username == 0) { if(nsd.options->username) nsd.username = nsd.options->username; else nsd.username = USER; } if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("cannot chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } /* EDNS0 */ edns_init_data(&nsd.edns_ipv4, nsd.options->ipv4_edns_size); #if defined(INET6) #if defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); #else /* no way to set IPV6 MTU, send no bigger than that. */ if (nsd.options->ipv6_edns_size < IPV6_MIN_MTU) edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size); else edns_init_data(&nsd.edns_ipv6, IPV6_MIN_MTU); #endif /* IPV6 MTU) */ #endif /* defined(INET6) */ if (nsd.nsid_len == 0 && nsd.options->nsid) { if (strlen(nsd.options->nsid) % 2 != 0) { error("the NSID must be a hex string of an even length."); } nsd.nsid = xalloc(strlen(nsd.options->nsid) / 2); nsd.nsid_len = strlen(nsd.options->nsid) / 2; if (hex_pton(nsd.options->nsid, nsd.nsid, nsd.nsid_len) == -1) { error("hex string cannot be parsed '%s' in NSID.", nsd.options->nsid); } } edns_init_nsid(&nsd.edns_ipv4, nsd.nsid_len); #if defined(INET6) edns_init_nsid(&nsd.edns_ipv6, nsd.nsid_len); #endif /* defined(INET6) */ /* Number of child servers to fork. */ nsd.children = (struct nsd_child *) region_alloc_array( nsd.region, nsd.child_count, sizeof(struct nsd_child)); for (i = 0; i < nsd.child_count; ++i) { nsd.children[i].kind = NSD_SERVER_BOTH; nsd.children[i].pid = -1; nsd.children[i].child_fd = -1; nsd.children[i].parent_fd = -1; nsd.children[i].handler = NULL; nsd.children[i].need_to_send_STATS = 0; nsd.children[i].need_to_send_QUIT = 0; nsd.children[i].need_to_exit = 0; nsd.children[i].has_exited = 0; #ifdef BIND8_STATS nsd.children[i].query_count = 0; #endif } nsd.this_child = NULL; /* We need at least one active interface */ if (nsd.ifs == 0) { add_interface(&nodes, &nsd, NULL); /* * With IPv6 we'd like to open two separate sockets, * one for IPv4 and one for IPv6, both listening to * the wildcard address (unless the -4 or -6 flags are * specified). * * However, this is only supported on platforms where * we can turn the socket option IPV6_V6ONLY _on_. * Otherwise we just listen to a single IPv6 socket * and any incoming IPv4 connections will be * automatically mapped to our IPv6 socket. */ #ifdef INET6 if (hints[0].ai_family == AF_UNSPEC) { #ifdef IPV6_V6ONLY add_interface(&nodes, &nsd, NULL); hints[0].ai_family = AF_INET6; hints[1].ai_family = AF_INET; hints_in_use = 2; nsd.grab_ip6_optional = 1; #else /* !IPV6_V6ONLY */ hints[0].ai_family = AF_INET6; #endif /* IPV6_V6ONLY */ } #endif /* INET6 */ } /* Set up the address info structures with real interface/port data */ assert(nodes); for (i = 0; i < nsd.ifs; ++i) { int r; const char* node = NULL; const char* service = NULL; int h = ((hints_in_use == 1)?0:i%hints_in_use); /* We don't perform name-lookups */ if (nodes[i] != NULL) hints[h].ai_flags |= AI_NUMERICHOST; get_ip_port_frm_str(nodes[i], &node, &service); hints[h].ai_socktype = SOCK_DGRAM; if ((r=getaddrinfo(node, (service?service:udp_port), &hints[h], &nsd.udp[i].addr)) != 0) { #ifdef INET6 if(nsd.grab_ip6_optional && hints[0].ai_family == AF_INET6) { log_msg(LOG_WARNING, "No IPv6, fallback to IPv4. getaddrinfo: %s", r==EAI_SYSTEM?strerror(errno):gai_strerror(r)); continue; } #endif error("cannot parse address '%s': getaddrinfo: %s %s", nodes[i]?nodes[i]:"(null)", gai_strerror(r), r==EAI_SYSTEM?strerror(errno):""); } hints[h].ai_socktype = SOCK_STREAM; if ((r=getaddrinfo(node, (service?service:tcp_port), &hints[h], &nsd.tcp[i].addr)) != 0) { error("cannot parse address '%s': getaddrinfo: %s %s", nodes[i]?nodes[i]:"(null)", gai_strerror(r), r==EAI_SYSTEM?strerror(errno):""); } } /* Parse the username into uid and gid */ nsd.gid = getgid(); nsd.uid = getuid(); #ifdef HAVE_GETPWNAM /* Parse the username into uid and gid */ if (*nsd.username) { if (isdigit((unsigned char)*nsd.username)) { char *t; nsd.uid = strtol(nsd.username, &t, 10); if (*t != 0) { if (*t != '.' || !isdigit((unsigned char)*++t)) { error("-u user or -u uid or -u uid.gid"); } nsd.gid = strtol(t, &t, 10); } else { /* Lookup the group id in /etc/passwd */ if ((pwd = getpwuid(nsd.uid)) == NULL) { error("user id %u does not exist.", (unsigned) nsd.uid); } else { nsd.gid = pwd->pw_gid; } } } else { /* Lookup the user id in /etc/passwd */ if ((pwd = getpwnam(nsd.username)) == NULL) { error("user '%s' does not exist.", nsd.username); } else { nsd.uid = pwd->pw_uid; nsd.gid = pwd->pw_gid; } } } /* endpwent(); */ #endif /* HAVE_GETPWNAM */ #if defined(HAVE_SSL) key_options_tsig_add(nsd.options); #endif append_trailing_slash(&nsd.options->xfrdir, nsd.options->region); /* Check relativity of pathnames to chroot */ if (nsd.chrootdir && nsd.chrootdir[0]) { /* existing chrootdir: append trailing slash for strncmp checking */ append_trailing_slash(&nsd.chrootdir, nsd.region); append_trailing_slash(&nsd.options->zonesdir, nsd.options->region); /* zonesdir must be absolute and within chroot, * all other pathnames may be relative to zonesdir */ if (strncmp(nsd.options->zonesdir, nsd.chrootdir, strlen(nsd.chrootdir)) != 0) { error("zonesdir %s has to be an absolute path that starts with the chroot path %s", nsd.options->zonesdir, nsd.chrootdir); } else if (!file_inside_chroot(nsd.pidfile, nsd.chrootdir)) { error("pidfile %s is not relative to %s: chroot not possible", nsd.pidfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.dbfile, nsd.chrootdir)) { error("database %s is not relative to %s: chroot not possible", nsd.dbfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdfile, nsd.chrootdir)) { error("xfrdfile %s is not relative to %s: chroot not possible", nsd.options->xfrdfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->zonelistfile, nsd.chrootdir)) { error("zonelistfile %s is not relative to %s: chroot not possible", nsd.options->zonelistfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdir, nsd.chrootdir)) { error("xfrdir %s is not relative to %s: chroot not possible", nsd.options->xfrdir, nsd.chrootdir); } } /* Set up the logging */ log_open(LOG_PID, FACILITY, nsd.log_filename); if (!nsd.log_filename) log_set_log_function(log_syslog); else if (nsd.uid && nsd.gid) { if(chown(nsd.log_filename, nsd.uid, nsd.gid) != 0) VERBOSITY(2, (LOG_WARNING, "chown %s failed: %s", nsd.log_filename, strerror(errno))); } log_msg(LOG_NOTICE, "%s starting (%s)", argv0, PACKAGE_STRING); /* Do we have a running nsd? */ if ((oldpid = readpid(nsd.pidfile)) == -1) { if (errno != ENOENT) { log_msg(LOG_ERR, "can't read pidfile %s: %s", nsd.pidfile, strerror(errno)); } } else { if (kill(oldpid, 0) == 0 || errno == EPERM) { log_msg(LOG_WARNING, "%s is already running as %u, continuing", argv0, (unsigned) oldpid); } else { log_msg(LOG_ERR, "...stale pid file from process %u", (unsigned) oldpid); } } /* Setup the signal handling... */ action.sa_handler = sig_handler; sigfillset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGTERM, &action, NULL); sigaction(SIGHUP, &action, NULL); sigaction(SIGINT, &action, NULL); sigaction(SIGILL, &action, NULL); sigaction(SIGUSR1, &action, NULL); sigaction(SIGALRM, &action, NULL); sigaction(SIGCHLD, &action, NULL); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); /* Initialize... */ nsd.mode = NSD_RUN; nsd.signal_hint_child = 0; nsd.signal_hint_reload = 0; nsd.signal_hint_reload_hup = 0; nsd.signal_hint_quit = 0; nsd.signal_hint_shutdown = 0; nsd.signal_hint_stats = 0; nsd.signal_hint_statsusr = 0; nsd.quit_sync_done = 0; /* Initialize the server... */ if (server_init(&nsd) != 0) { error("server initialization failed, %s could " "not be started", argv0); } #if defined(HAVE_SSL) if(nsd.options->control_enable) { /* read ssl keys while superuser and outside chroot */ if(!(nsd.rc = daemon_remote_create(nsd.options))) error("could not perform remote control setup"); } #endif /* HAVE_SSL */ /* Unless we're debugging, fork... */ if (!nsd.debug) { int fd; /* Take off... */ switch ((nsd.pid = fork())) { case 0: /* Child */ break; case -1: error("fork() failed: %s", strerror(errno)); break; default: /* Parent is done */ server_close_all_sockets(nsd.udp, nsd.ifs); server_close_all_sockets(nsd.tcp, nsd.ifs); exit(0); } /* Detach ourselves... */ if (setsid() == -1) { error("setsid() failed: %s", strerror(errno)); } if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > 2) (void)close(fd); } } /* Get our process id */ nsd.pid = getpid(); /* Set user context */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_SETUSERCONTEXT /* setusercontext does initgroups, setuid, setgid, and * also resource limits from login config, but we * still call setresuid, setresgid to be sure to set all uid */ if (setusercontext(NULL, pwd, nsd.uid, LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) log_msg(LOG_WARNING, "unable to setusercontext %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_SETUSERCONTEXT */ } #endif /* HAVE_GETPWNAM */ /* Chroot */ #ifdef HAVE_CHROOT if (nsd.chrootdir && nsd.chrootdir[0]) { int l = strlen(nsd.chrootdir)-1; /* ends in trailing slash */ if (file_inside_chroot(nsd.log_filename, nsd.chrootdir)) nsd.file_rotation_ok = 1; /* strip chroot from pathnames if they're absolute */ nsd.options->zonesdir += l; if (nsd.log_filename){ if (nsd.log_filename[0] == '/') nsd.log_filename += l; } if (nsd.pidfile[0] == '/') nsd.pidfile += l; if (nsd.dbfile[0] == '/') nsd.dbfile += l; if (nsd.options->xfrdfile[0] == '/') nsd.options->xfrdfile += l; if (nsd.options->zonelistfile[0] == '/') nsd.options->zonelistfile += l; if (nsd.options->xfrdir[0] == '/') nsd.options->xfrdir += l; /* strip chroot from pathnames of "include:" statements * on subsequent repattern commands */ cfg_parser->chroot = nsd.chrootdir; #ifdef HAVE_TZSET /* set timezone whilst not yet in chroot */ tzset(); #endif if (chroot(nsd.chrootdir)) { error("unable to chroot: %s", strerror(errno)); } if (chdir("/")) { error("unable to chdir to chroot: %s", strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", nsd.chrootdir)); /* chdir to zonesdir again after chroot */ if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { if(chdir(nsd.options->zonesdir)) { error("unable to chdir to '%s': %s", nsd.options->zonesdir, strerror(errno)); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", nsd.options->zonesdir)); } } else #endif /* HAVE_CHROOT */ nsd.file_rotation_ok = 1; DEBUG(DEBUG_IPC,1, (LOG_INFO, "file rotation on %s %sabled", nsd.log_filename, nsd.file_rotation_ok?"en":"dis")); /* Write pidfile */ if (writepid(&nsd) == -1) { log_msg(LOG_ERR, "cannot overwrite the pidfile %s: %s", nsd.pidfile, strerror(errno)); } /* Drop the permissions */ #ifdef HAVE_GETPWNAM if (*nsd.username) { #ifdef HAVE_INITGROUPS if(initgroups(nsd.username, nsd.gid) != 0) log_msg(LOG_WARNING, "unable to initgroups %s: %s", nsd.username, strerror(errno)); #endif /* HAVE_INITGROUPS */ endpwent(); #ifdef HAVE_SETRESGID if(setresgid(nsd.gid,nsd.gid,nsd.gid) != 0) #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) if(setregid(nsd.gid,nsd.gid) != 0) #else /* use setgid */ if(setgid(nsd.gid) != 0) #endif /* HAVE_SETRESGID */ error("unable to set group id of %s: %s", nsd.username, strerror(errno)); #ifdef HAVE_SETRESUID if(setresuid(nsd.uid,nsd.uid,nsd.uid) != 0) #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) if(setreuid(nsd.uid,nsd.uid) != 0) #else /* use setuid */ if(setuid(nsd.uid) != 0) #endif /* HAVE_SETRESUID */ error("unable to set user id of %s: %s", nsd.username, strerror(errno)); DEBUG(DEBUG_IPC,1, (LOG_INFO, "dropped user privileges, run as %s", nsd.username)); } #endif /* HAVE_GETPWNAM */ xfrd_make_tempdir(&nsd); #ifdef USE_ZONE_STATS options_zonestatnames_create(nsd.options); server_zonestat_alloc(&nsd); #endif /* USE_ZONE_STATS */ #ifdef USE_DNSTAP if(nsd.options->dnstap_enable) { nsd.dt_collector = dt_collector_create(&nsd); dt_collector_start(nsd.dt_collector, &nsd); } #endif /* USE_DNSTAP */ if(nsd.server_kind == NSD_SERVER_MAIN) { server_prepare_xfrd(&nsd); /* xfrd forks this before reading database, so it does not get * the memory size of the database */ server_start_xfrd(&nsd, 0, 0); /* close zonelistfile in non-xfrd processes */ zone_list_close(nsd.options); } if (server_prepare(&nsd) != 0) { unlinkpid(nsd.pidfile); error("server preparation failed, %s could " "not be started", argv0); } if(nsd.server_kind == NSD_SERVER_MAIN) { server_send_soa_xfrd(&nsd, 0); } /* Really take off */ log_msg(LOG_NOTICE, "%s started (%s), pid %d", argv0, PACKAGE_STRING, (int) nsd.pid); if (nsd.server_kind == NSD_SERVER_MAIN) { server_main(&nsd); } else { server_child(&nsd); } /* NOTREACH */ exit(0); } nsd-4.1.26/zlexer.c0000664000175000017500000016360513401455024013514 0ustar wouterwouter#include "config.h" #line 3 "" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 1 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yynoreturn yy_fatal_error (yyconst char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ (yytext_ptr) -= (yy_more_len); \ yyleng = (int) (yy_cp - (yytext_ptr)); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 25 #define YY_END_OF_BUFFER 26 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[70] = { 0, 0, 0, 0, 0, 16, 16, 20, 20, 26, 23, 14, 11, 11, 19, 24, 12, 13, 8, 1, 9, 23, 24, 6, 5, 16, 17, 16, 18, 20, 21, 22, 25, 23, 23, 14, 1, 1, 23, 23, 10, 15, 23, 7, 7, 7, 7, 6, 16, 16, 16, 16, 20, 0, 23, 23, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 3, 4, 0 } ; static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 7, 1, 1, 1, 8, 9, 1, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 12, 13, 13, 14, 15, 16, 13, 17, 13, 18, 13, 13, 19, 13, 20, 21, 13, 13, 22, 13, 23, 24, 13, 13, 13, 13, 13, 25, 26, 27, 1, 1, 1, 13, 13, 28, 29, 30, 13, 31, 13, 32, 13, 13, 33, 13, 34, 35, 13, 13, 36, 13, 37, 38, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst YY_CHAR yy_meta[39] = { 0, 1, 2, 3, 2, 4, 1, 1, 2, 2, 2, 2, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 } ; static yyconst flex_uint16_t yy_base[83] = { 0, 0, 25, 113, 112, 12, 14, 16, 17, 114, 87, 12, 218, 218, 218, 218, 218, 218, 218, 0, 86, 50, 59, 0, 218, 85, 218, 18, 218, 84, 218, 218, 103, 81, 95, 14, 0, 0, 76, 75, 74, 64, 120, 0, 28, 27, 27, 0, 63, 20, 59, 39, 57, 63, 5, 0, 41, 39, 48, 51, 55, 0, 49, 56, 63, 59, 79, 0, 0, 218, 146, 152, 158, 164, 170, 176, 182, 1, 188, 194, 199, 205, 211 } ; static yyconst flex_int16_t yy_def[83] = { 0, 70, 70, 71, 71, 72, 72, 73, 73, 69, 74, 69, 69, 69, 69, 69, 69, 69, 69, 75, 74, 76, 77, 78, 69, 79, 69, 80, 69, 81, 69, 69, 81, 74, 82, 69, 75, 75, 74, 74, 74, 74, 82, 77, 77, 77, 77, 78, 79, 80, 79, 80, 81, 81, 74, 42, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69 } ; static yyconst flex_uint16_t yy_nxt[257] = { 0, 69, 11, 12, 13, 14, 43, 15, 16, 17, 18, 19, 20, 69, 35, 26, 35, 26, 69, 30, 30, 31, 31, 36, 69, 36, 21, 11, 12, 13, 14, 34, 22, 16, 17, 18, 19, 20, 27, 28, 27, 28, 32, 32, 51, 48, 51, 48, 56, 57, 58, 21, 39, 39, 39, 59, 40, 60, 39, 39, 39, 39, 56, 57, 58, 51, 48, 61, 52, 59, 62, 60, 63, 64, 65, 41, 42, 44, 66, 67, 45, 61, 46, 53, 62, 49, 63, 64, 65, 49, 34, 44, 66, 67, 45, 68, 46, 33, 33, 33, 34, 34, 34, 33, 33, 33, 33, 34, 52, 68, 53, 49, 34, 34, 69, 24, 24, 69, 69, 69, 69, 55, 33, 33, 33, 69, 69, 69, 33, 33, 33, 33, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 55, 10, 10, 10, 10, 10, 10, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 29, 29, 29, 29, 29, 29, 33, 69, 69, 33, 33, 33, 37, 37, 69, 37, 37, 37, 38, 38, 38, 38, 38, 38, 47, 47, 69, 47, 47, 47, 48, 48, 69, 48, 48, 50, 50, 69, 50, 50, 50, 52, 52, 69, 69, 52, 52, 54, 54, 54, 54, 54, 54, 9, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69 } ; static yyconst flex_int16_t yy_chk[257] = { 0, 0, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 0, 11, 5, 35, 6, 0, 7, 8, 7, 8, 11, 0, 35, 1, 2, 2, 2, 2, 54, 2, 2, 2, 2, 2, 2, 5, 5, 6, 6, 7, 8, 27, 27, 49, 49, 44, 45, 46, 2, 21, 21, 21, 56, 21, 57, 21, 21, 21, 21, 44, 45, 46, 51, 51, 58, 53, 56, 59, 57, 60, 62, 63, 21, 21, 22, 64, 65, 22, 58, 22, 52, 59, 50, 60, 62, 63, 48, 41, 22, 64, 65, 22, 66, 22, 34, 34, 34, 40, 39, 38, 34, 34, 34, 34, 33, 32, 66, 29, 25, 20, 10, 9, 4, 3, 0, 0, 0, 0, 34, 42, 42, 42, 0, 0, 0, 42, 42, 42, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 74, 0, 0, 74, 74, 74, 75, 75, 0, 75, 75, 75, 76, 76, 76, 76, 76, 76, 78, 78, 0, 78, 78, 78, 79, 79, 0, 79, 79, 80, 80, 0, 80, 80, 80, 81, 81, 0, 0, 81, 81, 82, 82, 82, 82, 82, 82, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected static int yy_more_flag = 0; static int yy_more_len = 0; #define yymore() ((yy_more_flag) = 1) #define YY_MORE_ADJ (yy_more_len) #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "zlexer.lex" #line 2 "zlexer.lex" /* * zlexer.lex - lexical analyzer for (DNS) zone files * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif /* ignore fallthrough warnings in the generated parse code case statements */ #if defined(__clang__)||(defined(__GNUC__)&&(__GNUC__ >=7)) #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif #include "config.h" #include #include #include #include #include "zonec.h" #include "dname.h" #include "zparser.h" #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif enum lexer_state { EXPECT_OWNER, PARSING_OWNER, PARSING_TTL_CLASS_TYPE, PARSING_RDATA }; static int parse_token(int token, char *yytext, enum lexer_state *lexer_state); static YY_BUFFER_STATE include_stack[MAXINCLUDES]; static zparser_type zparser_stack[MAXINCLUDES]; static int include_stack_ptr = 0; /* * Saves the file specific variables on the include stack. */ static void push_parser_state(FILE *input) { zparser_stack[include_stack_ptr].filename = parser->filename; zparser_stack[include_stack_ptr].line = parser->line; zparser_stack[include_stack_ptr].origin = parser->origin; include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; yy_switch_to_buffer(yy_create_buffer(input,YY_BUF_SIZE)); ++include_stack_ptr; } /* * Restores the file specific variables from the include stack. */ static void pop_parser_state(void) { --include_stack_ptr; parser->filename = zparser_stack[include_stack_ptr].filename; parser->line = zparser_stack[include_stack_ptr].line; parser->origin = zparser_stack[include_stack_ptr].origin; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(include_stack[include_stack_ptr]); } static YY_BUFFER_STATE oldstate; /* Start string scan */ void parser_push_stringbuf(char* str) { oldstate = YY_CURRENT_BUFFER; yy_switch_to_buffer(yy_scan_string(str)); } void parser_pop_stringbuf(void) { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(oldstate); 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) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer(yyin,YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif #define YY_NO_INPUT 1 #line 117 "zlexer.lex" #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif #line 653 "" #define INITIAL 0 #define incl 1 #define bitlabel 2 #define quotedstring 3 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (void ); int yyget_debug (void ); void yyset_debug (int debug_flag ); YY_EXTRA_TYPE yyget_extra (void ); void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); void yyset_in (FILE * _in_str ); FILE *yyget_out (void ); void yyset_out (FILE * _out_str ); int yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); void yyset_lineno (int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } { #line 139 "zlexer.lex" #line 877 "" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { (yy_more_len) = 0; if ( (yy_more_flag) ) { (yy_more_len) = (yy_c_buf_p) - (yytext_ptr); (yy_more_flag) = 0; } yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 70 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 218 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 140 "zlexer.lex" /* ignore */ YY_BREAK case 2: YY_RULE_SETUP #line 141 "zlexer.lex" { lexer_state = PARSING_RDATA; return DOLLAR_TTL; } YY_BREAK case 3: YY_RULE_SETUP #line 142 "zlexer.lex" { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; } YY_BREAK /* * Handle $INCLUDE directives. See * http://dinosaur.compilertools.net/flex/flex_12.html#SEC12. */ case 4: YY_RULE_SETUP #line 148 "zlexer.lex" { BEGIN(incl); /* ignore case statement fallthrough on incl flex rule */ } YY_BREAK case 5: /* rule 5 can match eol */ #line 153 "zlexer.lex" YY_RULE_SETUP case YY_STATE_EOF(incl): #line 153 "zlexer.lex" { int error_occurred = parser->error_occurred; BEGIN(INITIAL); zc_error("missing file name in $INCLUDE directive"); yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ ++parser->line; parser->error_occurred = error_occurred; } YY_BREAK case 6: YY_RULE_SETUP #line 161 "zlexer.lex" { char *tmp; domain_type *origin = parser->origin; int error_occurred = parser->error_occurred; BEGIN(INITIAL); if (include_stack_ptr >= MAXINCLUDES ) { zc_error("includes nested too deeply, skipped (>%d)", MAXINCLUDES); } else { FILE *input; /* Remove trailing comment. */ tmp = strrchr(yytext, ';'); if (tmp) { *tmp = '\0'; } strip_string(yytext); /* Parse origin for include file. */ tmp = strrchr(yytext, ' '); if (!tmp) { tmp = strrchr(yytext, '\t'); } if (tmp) { const dname_type *dname; /* split the original yytext */ *tmp = '\0'; strip_string(yytext); dname = dname_parse(parser->region, tmp + 1); if (!dname) { zc_error("incorrect include origin '%s'", tmp + 1); } else if (*(tmp + strlen(tmp + 1)) != '.') { zc_error("$INCLUDE directive requires absolute domain name"); } else { origin = domain_table_insert( parser->db->domains, dname); } } if (strlen(yytext) == 0) { zc_error("missing file name in $INCLUDE directive"); } else if (!(input = fopen(yytext, "r"))) { zc_error("cannot open include file '%s': %s", yytext, strerror(errno)); } else { /* Initialize parser for include file. */ char *filename = region_strdup(parser->region, yytext); push_parser_state(input); /* Destroys yytext. */ parser->filename = filename; parser->line = 1; parser->origin = origin; lexer_state = EXPECT_OWNER; } } parser->error_occurred = error_occurred; } YY_BREAK case YY_STATE_EOF(INITIAL): #line 222 "zlexer.lex" { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (include_stack_ptr == 0) { yyterminate(); } else { fclose(yyin); pop_parser_state(); } } YY_BREAK case 7: YY_RULE_SETUP #line 231 "zlexer.lex" { zc_warning("Unknown directive: %s", yytext); } YY_BREAK case 8: YY_RULE_SETUP #line 232 "zlexer.lex" { LEXOUT((". ")); return parse_token('.', yytext, &lexer_state); } YY_BREAK case 9: YY_RULE_SETUP #line 236 "zlexer.lex" { LEXOUT(("@ ")); return parse_token('@', yytext, &lexer_state); } YY_BREAK case 10: YY_RULE_SETUP #line 240 "zlexer.lex" { LEXOUT(("\\# ")); return parse_token(URR, yytext, &lexer_state); } YY_BREAK case 11: /* rule 11 can match eol */ YY_RULE_SETUP #line 244 "zlexer.lex" { ++parser->line; if (!paren_open) { lexer_state = EXPECT_OWNER; LEXOUT(("NL\n")); return NL; } else { LEXOUT(("SP ")); return SP; } } YY_BREAK case 12: YY_RULE_SETUP #line 255 "zlexer.lex" { if (paren_open) { zc_error("nested parentheses"); yyterminate(); } LEXOUT(("( ")); paren_open = 1; return SP; } YY_BREAK case 13: YY_RULE_SETUP #line 264 "zlexer.lex" { if (!paren_open) { zc_error("closing parentheses without opening parentheses"); yyterminate(); } LEXOUT((") ")); paren_open = 0; return SP; } YY_BREAK case 14: YY_RULE_SETUP #line 273 "zlexer.lex" { if (!paren_open && lexer_state == EXPECT_OWNER) { lexer_state = PARSING_TTL_CLASS_TYPE; LEXOUT(("PREV ")); return PREV; } if (lexer_state == PARSING_OWNER) { lexer_state = PARSING_TTL_CLASS_TYPE; } LEXOUT(("SP ")); return SP; } YY_BREAK /* Bitlabels. Strip leading and ending brackets. */ case 15: YY_RULE_SETUP #line 287 "zlexer.lex" { BEGIN(bitlabel); } YY_BREAK case YY_STATE_EOF(bitlabel): #line 288 "zlexer.lex" { zc_error("EOF inside bitlabel"); BEGIN(INITIAL); yyrestart(yyin); /* this is so that lex does not give an internal err */ yyterminate(); } YY_BREAK case 16: YY_RULE_SETUP #line 294 "zlexer.lex" { yymore(); } YY_BREAK case 17: /* rule 17 can match eol */ YY_RULE_SETUP #line 295 "zlexer.lex" { ++parser->line; yymore(); } YY_BREAK case 18: YY_RULE_SETUP #line 296 "zlexer.lex" { BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; return parse_token(BITLAB, yytext, &lexer_state); } YY_BREAK /* Quoted strings. Strip leading and ending quotes. */ case 19: YY_RULE_SETUP #line 303 "zlexer.lex" { BEGIN(quotedstring); LEXOUT(("\" ")); } YY_BREAK case YY_STATE_EOF(quotedstring): #line 304 "zlexer.lex" { zc_error("EOF inside quoted string"); BEGIN(INITIAL); yyrestart(yyin); /* this is so that lex does not give an internal err */ yyterminate(); } YY_BREAK case 20: YY_RULE_SETUP #line 310 "zlexer.lex" { LEXOUT(("STR ")); yymore(); } YY_BREAK case 21: /* rule 21 can match eol */ YY_RULE_SETUP #line 311 "zlexer.lex" { ++parser->line; yymore(); } YY_BREAK case 22: YY_RULE_SETUP #line 312 "zlexer.lex" { LEXOUT(("\" ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; return parse_token(STR, yytext, &lexer_state); } YY_BREAK case 23: /* rule 23 can match eol */ YY_RULE_SETUP #line 319 "zlexer.lex" { /* Any allowed word. */ return parse_token(STR, yytext, &lexer_state); } YY_BREAK case 24: YY_RULE_SETUP #line 323 "zlexer.lex" { zc_error("unknown character '%c' (\\%03d) seen - is this a zonefile?", (int) yytext[0], (int) yytext[0]); } YY_BREAK case 25: YY_RULE_SETUP #line 327 "zlexer.lex" ECHO; YY_BREAK #line 1240 "" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,(yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,(yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 70 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 70 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; yy_is_jam = (yy_current_state == 69); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc((yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,(int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 327 "zlexer.lex" /* * Analyze "word" to see if it matches an RR type, possibly by using * the "TYPExxx" notation. If it matches, the corresponding token is * returned and the TYPE parameter is set to the RR type value. */ static int rrtype_to_token(const char *word, uint16_t *type) { uint16_t t = rrtype_from_string(word); if (t != 0) { rrtype_descriptor_type *entry = rrtype_descriptor_by_type(t); *type = t; return entry->token; } return 0; } /* * Remove \DDD constructs from the input. See RFC 1035, section 5.1. */ static size_t zoctet(char *text) { /* * s follows the string, p lags behind and rebuilds the new * string */ char *s; char *p; for (s = p = text; *s; ++s, ++p) { assert(p <= s); if (s[0] != '\\') { /* Ordinary character. */ *p = *s; } else if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) { /* \DDD escape. */ int val = (hexdigit_to_int(s[1]) * 100 + hexdigit_to_int(s[2]) * 10 + hexdigit_to_int(s[3])); if (0 <= val && val <= 255) { s += 3; *p = val; } else { zc_warning("text escape \\DDD overflow"); *p = *++s; } } else if (s[1] != '\0') { /* \X where X is any character, keep X. */ *p = *++s; } else { /* Trailing backslash, ignore it. */ zc_warning("trailing backslash ignored"); --p; } } *p = '\0'; return p - text; } static int parse_token(int token, char *yytext, enum lexer_state *lexer_state) { size_t len; char *str; if (*lexer_state == EXPECT_OWNER) { *lexer_state = PARSING_OWNER; } else if (*lexer_state == PARSING_TTL_CLASS_TYPE) { const char *t; int token; uint16_t rrclass; /* type */ token = rrtype_to_token(yytext, &yylval.type); if (token != 0) { *lexer_state = PARSING_RDATA; LEXOUT(("%d[%s] ", token, yytext)); return token; } /* class */ rrclass = rrclass_from_string(yytext); if (rrclass != 0) { yylval.klass = rrclass; LEXOUT(("CLASS ")); return T_RRCLASS; } /* ttl */ yylval.ttl = strtottl(yytext, &t); if (*t == '\0') { LEXOUT(("TTL ")); return T_TTL; } } str = region_strdup(parser->rr_region, yytext); len = zoctet(str); yylval.data.str = str; yylval.data.len = len; LEXOUT(("%d[%s] ", token, yytext)); return token; } nsd-4.1.26/udbzone.h0000664000175000017500000001234713040156013013645 0ustar wouterwouter/* * udbzone -- store zone and rrset information in udb file. * * Copyright (c) 2011, NLnet Labs. See LICENSE for license. */ #ifndef UDB_ZONE_H #define UDB_ZONE_H #include "udb.h" #include "dns.h" #include "udbradtree.h" /** * Store the DNS information in udb file on disk. * udb_global * | * v * zonetree -> zone -- zone_name * radtree |--> nsec3param * |--> log_str * |--> file_str * | * v * domain --> rrset -> rr * radtree list list * |-- name */ /** zone information in the nsd.udb. Name allocated after it. */ struct zone_d { /** radtree node in the zonetree for this zone */ udb_rel_ptr node; /** the radtree for the domain names in the zone */ udb_rel_ptr domains; /** the NSEC3PARAM rr used for hashing (or 0), rr_d pointer */ udb_rel_ptr nsec3param; /** the log_str for the AXFR change, or 0 */ udb_rel_ptr log_str; /** the file name when read from a file, or 0 */ udb_rel_ptr file_str; /** modification time, time when the zone data was changed */ uint64_t mtime; /** modification time, nsecs */ uint64_t mtime_nsec; /** number of RRsets in the zone */ uint64_t rrset_count; /** number of RRs in the zone */ uint64_t rr_count; /** the length of the zone name */ udb_radstrlen_type namelen; /** if the zone is expired */ uint8_t expired; /** if the zone has been changed by AXFR */ uint8_t is_changed; /** the zone (wire uncompressed) name in DNS format */ uint8_t name[0]; }; /** domain name in the nametree. name allocated after it */ struct domain_d { /** radtree node in the nametree for this domain */ udb_rel_ptr node; /** the list of rrsets for this name, single linked */ udb_rel_ptr rrsets; /** length of the domain name */ udb_radstrlen_type namelen; /** the domain (wire uncompressed) name in DNS format */ uint8_t name[0]; }; /** rrset information. */ struct rrset_d { /** next in rrset list */ udb_rel_ptr next; /** the singly linked list of rrs for this rrset */ udb_rel_ptr rrs; /** type of the RRs in this rrset (host order) */ uint16_t type; }; /** rr information; wireformat data allocated after it */ struct rr_d { /** next in rr list */ udb_rel_ptr next; /** type (host order) */ uint16_t type; /** class (host order) */ uint16_t klass; /** ttl (host order) */ uint32_t ttl; /** length of wireformat */ uint16_t len; /** wireformat of rdata (without rdatalen) */ uint8_t wire[0]; }; /** init an udb for use as DNS store */ int udb_dns_init_file(udb_base* udb); /** de-init an udb for use as DNS store */ void udb_dns_deinit_file(udb_base* udb); /** create a zone */ int udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname, size_t dlen); /** clear all RRsets from a zone */ void udb_zone_clear(udb_base* udb, udb_ptr* zone); /** delete a zone */ void udb_zone_delete(udb_base* udb, udb_ptr* zone); /** find a zone by name (exact match) */ int udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname, size_t dlen); /** get modification time for zone or 0 */ void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen, struct timespec* mtime); /** set log str in udb, or remove it */ void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str); /** set file str in udb, or remove it */ void udb_zone_set_file_str(udb_base* udb, udb_ptr* zone, const char* str); /** get file string for zone or NULL */ const char* udb_zone_get_file_str(udb_base* udb, const uint8_t* dname, size_t dlen); /** find a domain name in the zone domain tree */ int udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, udb_ptr* result); /** find rrset in domain */ int udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res); /** add an RR to a zone */ int udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen); /** del an RR from a zone */ void udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen); /** get pretty string for nsec3parameters (static buffer returned) */ const char* udb_nsec3param_string(udb_ptr* rr); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_zone */ void udb_zone_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_domain */ void udb_domain_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_rrset */ void udb_rrset_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_rr */ void udb_rr_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** walk through relptrs in registered types */ void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); #define ZONE(ptr) ((struct zone_d*)UDB_PTR(ptr)) #define DOMAIN(ptr) ((struct domain_d*)UDB_PTR(ptr)) #define RRSET(ptr) ((struct rrset_d*)UDB_PTR(ptr)) #define RR(ptr) ((struct rr_d*)UDB_PTR(ptr)) #endif /* UDB_ZONE_H */ nsd-4.1.26/mini_event.c0000664000175000017500000002463513040156013014332 0ustar wouterwouter/* * mini_event.c - implementation of part of libevent api, portably. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * \file * fake libevent implementation. Less broad in functionality, and only * supports select(2). */ #include "config.h" #ifdef HAVE_TIME_H #include #endif #include #include #include #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) #ifdef HAVE_WINSOCK2_H #define FD_SET_T (u_int) #else #define FD_SET_T #endif #include #include "mini_event.h" #include "util.h" /** compare events in tree, based on timevalue, ptr for uniqueness */ int mini_ev_cmp(const void* a, const void* b) { const struct event* e = (const struct event*)a; const struct event* f = (const struct event*)b; if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec) return -1; if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec) return 1; if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec) return -1; if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec) return 1; if(e < f) return -1; if(e > f) return 1; return 0; } /** set time */ static int settime(struct event_base* base) { if(gettimeofday(base->time_tv, NULL) < 0) { return -1; } #ifndef S_SPLINT_S *base->time_secs = (time_t)base->time_tv->tv_sec; #endif return 0; } /** create event base */ void * event_init(time_t* time_secs, struct timeval* time_tv) { struct event_base* base = (struct event_base*)malloc( sizeof(struct event_base)); if(!base) return NULL; memset(base, 0, sizeof(*base)); base->region = region_create(xalloc, free); if(!base->region) { free(base); return NULL; } base->time_secs = time_secs; base->time_tv = time_tv; if(settime(base) < 0) { event_base_free(base); return NULL; } base->times = rbtree_create(base->region, mini_ev_cmp); if(!base->times) { event_base_free(base); return NULL; } base->capfd = MAX_FDS; #ifdef FD_SETSIZE if((int)FD_SETSIZE < base->capfd) base->capfd = (int)FD_SETSIZE; #endif base->fds = (struct event**)calloc((size_t)base->capfd, sizeof(struct event*)); if(!base->fds) { event_base_free(base); return NULL; } base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*)); if(!base->signals) { event_base_free(base); return NULL; } #ifndef S_SPLINT_S FD_ZERO(&base->reads); FD_ZERO(&base->writes); #endif return base; } /** get version */ const char * event_get_version(void) { return "mini-event-"PACKAGE_VERSION; } /** get polling method, select */ const char * event_get_method(void) { return "select"; } /** call timeouts handlers, and return how long to wait for next one or -1 */ static int handle_timeouts(struct event_base* base, struct timeval* now, struct timeval* wait) { struct event* p; int tofired = 0; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } return tofired; } #endif /* event times out, remove it */ tofired = 1; (void)rbtree_delete(base->times, p); p->ev_flags &= ~EV_TIMEOUT; (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } return tofired; } /** call select and callbacks for that */ static int handle_select(struct event_base* base, struct timeval* wait) { fd_set r, w; int ret, i; #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { ret = errno; if(settime(base) < 0) return -1; errno = ret; if(ret == EAGAIN || ret == EINTR) return 0; return -1; } if(settime(base) < 0) return -1; for(i=0; imaxfd+1; i++) { short bits = 0; if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { continue; } if(FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if(FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->fds[i]->ev_flags; if(bits) { (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, bits, base->fds[i]->ev_arg); if(ret==0) break; } } return 0; } /** run select once */ int event_base_loop(struct event_base* base, int flags) { struct timeval wait; if(!(flags & EVLOOP_ONCE)) return event_base_dispatch(base); /* see if timeouts need handling */ if(handle_timeouts(base, base->time_tv, &wait)) return 0; /* there were timeouts, end of loop */ if(base->need_to_exit) return 0; /* do select */ if(handle_select(base, &wait) < 0) { if(base->need_to_exit) return 0; return -1; } return 0; } /** run select in a loop */ int event_base_dispatch(struct event_base* base) { struct timeval wait; if(settime(base) < 0) return -1; while(!base->need_to_exit) { /* see if timeouts need handling */ (void)handle_timeouts(base, base->time_tv, &wait); if(base->need_to_exit) return 0; /* do select */ if(handle_select(base, &wait) < 0) { if(base->need_to_exit) return 0; return -1; } } return 0; } /** exit that loop */ int event_base_loopexit(struct event_base* base, struct timeval* ATTR_UNUSED(tv)) { base->need_to_exit = 1; return 0; } /* free event base, free events yourself */ void event_base_free(struct event_base* base) { if(!base) return; if(base->times) free(base->times); if(base->fds) free(base->fds); if(base->signals) free(base->signals); region_destroy(base->region); free(base); } /** set content of event */ void event_set(struct event* ev, int fd, short bits, void (*cb)(int, short, void *), void* arg) { ev->node.key = ev; ev->ev_fd = fd; ev->ev_flags = bits; ev->ev_callback = cb; ev->ev_arg = arg; ev->added = 0; } /* add event to a base */ int event_base_set(struct event_base* base, struct event* ev) { ev->ev_base = base; ev->added = 0; return 0; } /* add event to make it active, you may not change it with event_set anymore */ int event_add(struct event* ev, struct timeval* tv) { if(ev->added) event_del(ev); if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) return -1; if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { ev->ev_base->fds[ev->ev_fd] = ev; if(ev->ev_flags&EV_READ) { FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads); } if(ev->ev_flags&EV_WRITE) { FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes); } FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); if(ev->ev_fd > ev->ev_base->maxfd) ev->ev_base->maxfd = ev->ev_fd; } if(tv && (ev->ev_flags&EV_TIMEOUT)) { #ifndef S_SPLINT_S struct timeval* now = ev->ev_base->time_tv; ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; while(ev->ev_timeout.tv_usec > 1000000) { ev->ev_timeout.tv_usec -= 1000000; ev->ev_timeout.tv_sec++; } #endif (void)rbtree_insert(ev->ev_base->times, &ev->node); } ev->added = 1; return 0; } /* remove event, you may change it again */ int event_del(struct event* ev) { if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd) return -1; if((ev->ev_flags&EV_TIMEOUT)) (void)rbtree_delete(ev->ev_base->times, &ev->node); if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { ev->ev_base->fds[ev->ev_fd] = NULL; FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready); FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content); } ev->added = 0; return 0; } /** which base gets to handle signals */ static struct event_base* signal_base = NULL; /** signal handler */ static RETSIGTYPE sigh(int sig) { struct event* ev; if(!signal_base || sig < 0 || sig >= MAX_SIG) return; ev = signal_base->signals[sig]; if(!ev) return; (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); } /** install signal handler */ int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv)) { struct sigaction action; if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) return -1; signal_base = ev->ev_base; ev->ev_base->signals[ev->ev_fd] = ev; ev->added = 1; action.sa_handler = sigh; sigfillset(&action.sa_mask); action.sa_flags = 0; return sigaction(ev->ev_fd, &action, NULL); } /** remove signal handler */ int signal_del(struct event* ev) { if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG) return -1; ev->ev_base->signals[ev->ev_fd] = NULL; ev->added = 0; return 0; } #else /* USE_MINI_EVENT */ #ifndef USE_WINSOCK int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) { return 0; } #endif /* not USE_WINSOCK */ #endif /* USE_MINI_EVENT */ nsd-4.1.26/dname.h0000664000175000017500000002117412623035675013301 0ustar wouterwouter/* * dname.h -- Domain name handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _DNAME_H_ #define _DNAME_H_ #include #include #include "buffer.h" #include "region-allocator.h" #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE) #define DNAME_NORMALIZE toupper #else #define DNAME_NORMALIZE tolower #endif /* * Domain names stored in memory add some additional information to be * able to quickly index and compare by label. */ typedef struct dname dname_type; struct dname { /* * The size (in bytes) of the domain name in wire format. */ uint8_t name_size; /* * The number of labels in this domain name (including the * root label). */ uint8_t label_count; /* uint8_t label_offsets[label_count]; uint8_t name[name_size]; */ }; /* * Construct a new domain name based on NAME in wire format. NAME * cannot contain compression pointers. * * Pre: NAME != NULL. */ const dname_type *dname_make(region_type *region, const uint8_t *name, int normalize); /* * Construct a new domain name based on wire format dname stored at * PACKET's current position. Compression pointers are followed. The * PACKET's current position is changed to the end of the wire format * dname or set to just after the first compression pointer. */ const dname_type *dname_make_from_packet(region_type *region, buffer_type *packet, int allow_pointers, int normalize); /* * parse wireformat from packet (following pointers) into the * given buffer. Returns length in buffer or 0 on error. * buffer must be MAXDOMAINLEN+1 long. */ int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers); /* * Construct a new domain name based on the ASCII representation NAME. * If ORIGIN is not NULL and NAME is not terminated by a "." the * ORIGIN is appended to the result. NAME can contain escape * sequences. * * Returns NULL on failure. Otherwise a newly allocated domain name * is returned. * * Pre: name != NULL. */ const dname_type *dname_parse(region_type *region, const char *name); /* * parse ascii string to wireformat domain name (without compression ptrs) * returns 0 on failure, the length of the wireformat on success. * the result is stored in the wirefmt which must be at least MAXDOMAINLEN * in size. On failure, the wirefmt can be altered. */ int dname_parse_wire(uint8_t* wirefmt, const char* name); /* * Return NULL if DNAME is NULL or a copy of DNAME otherwise. */ const dname_type *dname_copy(region_type *region, const dname_type *dname); /* * Copy the most significant LABEL_COUNT labels from dname. */ const dname_type *dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count); /* * The origin of DNAME. */ const dname_type *dname_origin(region_type *region, const dname_type *dname); /* * Return true if LEFT is a subdomain of RIGHT. */ int dname_is_subdomain(const dname_type *left, const dname_type *right); /* * Offsets into NAME for each label starting with the most * significant label (the root label, followed by the TLD, * etc). */ static inline const uint8_t * dname_label_offsets(const dname_type *dname) { return (const uint8_t *) ((const char *) dname + sizeof(dname_type)); } /* * The actual name in wire format (a sequence of label, each * prefixed by a length byte, terminated by a zero length * label). */ static inline const uint8_t * dname_name(const dname_type *dname) { return (const uint8_t *) ((const char *) dname + sizeof(dname_type) + dname->label_count * sizeof(uint8_t)); } /* * Return the label for DNAME specified by LABEL_INDEX. The first * label (LABEL_INDEX == 0) is the root label, the next label is the * TLD, etc. * * Pre: dname != NULL && label_index < dname->label_count. */ static inline const uint8_t * dname_label(const dname_type *dname, uint8_t label) { uint8_t label_index; assert(dname != NULL); assert(label < dname->label_count); label_index = dname_label_offsets(dname)[label]; assert(label_index < dname->name_size); return dname_name(dname) + label_index; } /* * Compare two domain names. The comparison defines a lexicographical * ordering based on the domain name's labels, starting with the most * significant label. * * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT > * RIGHT. The comparison is case sensitive. * * Pre: left != NULL && right != NULL */ int dname_compare(const dname_type *left, const dname_type *right); /* * Compare two labels. The comparison defines a lexicographical * ordering based on the characters in the labels. * * Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT > * RIGHT. The comparison is case sensitive. * * Pre: left != NULL && right != NULL * label_is_normal(left) && label_is_normal(right) */ int label_compare(const uint8_t *left, const uint8_t *right); /* * Returns the number of labels that match in LEFT and RIGHT, starting * with the most significant label. Because the root label always * matches, the result will always be >= 1. * * Pre: left != NULL && right != NULL */ uint8_t dname_label_match_count(const dname_type *left, const dname_type *right); /* * The total size (in bytes) allocated to store DNAME. * * Pre: dname != NULL */ static inline size_t dname_total_size(const dname_type *dname) { return (sizeof(dname_type) + ((((size_t)dname->label_count) + ((size_t)dname->name_size)) * sizeof(uint8_t))); } /* * Is LABEL a normal LABEL (not a pointer or reserved)? * * Pre: label != NULL; */ static inline int label_is_normal(const uint8_t *label) { assert(label); return (label[0] & 0xc0) == 0; } /* * Is LABEL a pointer? * * Pre: label != NULL; */ static inline int label_is_pointer(const uint8_t *label) { assert(label); return (label[0] & 0xc0) == 0xc0; } /* * LABEL's pointer location. * * Pre: label != NULL && label_is_pointer(label) */ static inline uint16_t label_pointer_location(const uint8_t *label) { assert(label); assert(label_is_pointer(label)); return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1]; } /* * Length of LABEL. * * Pre: label != NULL && label_is_normal(label) */ static inline uint8_t label_length(const uint8_t *label) { assert(label); assert(label_is_normal(label)); return label[0]; } /* * The data of LABEL. * * Pre: label != NULL && label_is_normal(label) */ static inline const uint8_t * label_data(const uint8_t *label) { assert(label); assert(label_is_normal(label)); return label + 1; } /* * Is LABEL the root label? * * Pre: label != NULL */ static inline int label_is_root(const uint8_t *label) { assert(label); return label[0] == 0; } /* * Is LABEL the wildcard label? * * Pre: label != NULL */ static inline int label_is_wildcard(const uint8_t *label) { assert(label); return label[0] == 1 && label[1] == '*'; } /* * The next label of LABEL. * * Pre: label != NULL * label_is_normal(label) * !label_is_root(label) */ static inline const uint8_t * label_next(const uint8_t *label) { assert(label); assert(label_is_normal(label)); assert(!label_is_root(label)); return label + label_length(label) + 1; } /* * Convert DNAME to its string representation. The result points to a * static buffer that is overwritten the next time this function is * invoked. * * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname * will be represented relative to ORIGIN. * * Pre: dname != NULL */ const char *dname_to_string(const dname_type *dname, const dname_type *origin); /* * Create a dname containing the single label specified by STR * followed by the root label. */ const dname_type *dname_make_from_label(region_type *region, const uint8_t *label, const size_t length); /* * Concatenate two dnames. */ const dname_type *dname_concatenate(region_type *region, const dname_type *left, const dname_type *right); /* * Perform DNAME substitution on a name, replace src with dest. * Name must be a subdomain of src. The returned name is a subdomain of dest. * Returns NULL if the result domain name is too long. */ const dname_type *dname_replace(region_type* region, const dname_type* name, const dname_type* src, const dname_type* dest); /** Convert uncompressed wireformat dname to a string */ char* wiredname2str(const uint8_t* dname); /** convert uncompressed label to string */ char* wirelabel2str(const uint8_t* label); /** check if two uncompressed dnames of the same total length are equal */ int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len); #endif /* _DNAME_H_ */ nsd-4.1.26/remote.h0000664000175000017500000000751613325342426013507 0ustar wouterwouter/* * remote.h - remote control for the NSD daemon. * * Copyright (c) 2008, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file contains the remote control functionality for the daemon. * The remote control can be performed using either the commandline * nsd-control tool, or a SSLv3/TLS capable web browser. * The channel is secured using SSLv3 or TLSv1, and certificates. * Both the server and the client(control tool) have their own keys. */ #ifndef DAEMON_REMOTE_H #define DAEMON_REMOTE_H struct xfrd_state; struct nsd_options; /* private, defined in remote.c to keep ssl.h out of this header */ struct daemon_remote; struct rc_state; /* the remote control needs less backlog than the tcp53 service */ #define TCP_BACKLOG_REMOTE 16 /* listen() tcp backlog */ /** * Create new remote control state for the daemon. * Also setups the control port. * @param cfg: config file with key file settings. * @return new state, or NULL on failure. */ struct daemon_remote* daemon_remote_create(struct nsd_options* cfg); /** * remote control state to delete. * @param rc: state to delete. */ void daemon_remote_delete(struct daemon_remote* rc); /** * Close remote control ports. Clears up busy connections. * Does not delete the rc itself, or the ssl context (with its keys). * @param rc: state to close. */ void daemon_remote_close(struct daemon_remote* rc); /** * Open and create listening ports for remote control. * @param rc: rc state that contains list of accept port sockets. * @param cfg: config options. * @return false on failure. */ int daemon_remote_open_ports(struct daemon_remote* rc, struct nsd_options* cfg); /** * Setup comm points for accepting remote control connections. * @param rc: state * @param xfrd: the process that hosts the control connection. * The rc is attached to its event base. */ void daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd); /** * Process statistic results and send them * @param rc: state. */ void daemon_remote_process_stats(struct daemon_remote* rc); /** * Create and bind local listening socket * @param path: path to the socket. * @param noproto: on error, this is set true if cause is that local sockets * are not supported. * @return: the socket. -1 on error. */ int create_local_accept_sock(const char* path, int* noproto); #endif /* DAEMON_REMOTE_H */ nsd-4.1.26/netio.h0000664000175000017500000001242312612426434013323 0ustar wouterwouter/* * netio.h -- network I/O support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The netio module implements event based I/O handling using * pselect(2). Multiple event handlers can wait for a certain event * to occur simultaneously. Each event handler is called when an * event occurs that the event handler has indicated that it is * willing to handle. * * There are four types of events that can be handled: * * NETIO_EVENT_READ: reading will not block. * NETIO_EVENT_WRITE: writing will not block. * NETIO_EVENT_TIMEOUT: the timeout expired. * * A file descriptor must be specified if the handler is interested in * the first three event types. A timeout must be specified if the * event handler is interested in timeouts. These event types can be * OR'ed together if the handler is willing to handle multiple types * of events. * * The special event type NETIO_EVENT_NONE is available if you wish to * temporarily disable the event handler without removing and adding * the handler to the netio structure. * * The event callbacks are free to modify the netio_handler_type * structure to change the file descriptor, timeout, event types, user * data, or handler functions. * * The main loop of the program must call netio_dispatch to check for * events and dispatch them to the handlers. An additional timeout * can be specified as well as the signal mask to install while * blocked in pselect(2). */ #ifndef _NETIO_H_ #define _NETIO_H_ #ifdef HAVE_SYS_SELECT_H #include #endif #include #include "region-allocator.h" /* * The type of events a handler is interested in. These can be OR'ed * together to specify multiple event types. */ enum netio_event_types { NETIO_EVENT_NONE = 0, NETIO_EVENT_READ = 1, NETIO_EVENT_WRITE = 2, NETIO_EVENT_TIMEOUT = 4, }; typedef enum netio_event_types netio_event_types_type; typedef struct netio netio_type; typedef struct netio_handler netio_handler_type; typedef struct netio_handler_list netio_handler_list_type; struct netio { region_type *region; netio_handler_list_type *handlers; netio_handler_list_type *deallocated; /* * Cached value of the current time. The cached value is * cleared at the start of netio_dispatch to calculate the * relative timeouts of the event handlers and after calling * pselect(2) so handlers can use it to calculate a new * absolute timeout. * * Use netio_current_time() to read the current time. */ int have_current_time; struct timespec cached_current_time; /* * Next handler in the dispatch. Only valid during callbacks. * To make sure that deletes respect the state of the iterator. */ netio_handler_list_type *dispatch_next; }; typedef void (*netio_event_handler_type)(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types); struct netio_handler { /* * The file descriptor that should be checked for events. If * the file descriptor is negative only timeout events are * checked for. */ int fd; /** index of the pollfd array for this handler */ int pfd; /* * The time when no events should be checked for and the * handler should be called with the NETIO_EVENT_TIMEOUT * event type. Unlike most timeout parameters the time should * be absolute, not relative! */ struct timespec *timeout; /* * Additional user data. */ void *user_data; /* * The type of events that should be checked for. These types * can be OR'ed together to wait for multiple types of events. */ netio_event_types_type event_types; /* * The event handler. The event_types parameter contains the * OR'ed set of event types that actually triggered. The * event handler is allowed to modify this handler object. * The event handler SHOULD NOT block. */ netio_event_handler_type event_handler; }; struct netio_handler_list { netio_handler_list_type *next; netio_handler_type *handler; }; /* * Create a new netio instance using the specified REGION. The netio * instance is cleaned up when the REGION is deallocated. */ netio_type *netio_create(region_type *region); /* * Add a new HANDLER to NETIO. */ void netio_add_handler(netio_type *netio, netio_handler_type *handler); /* * Remove the HANDLER from NETIO. */ void netio_remove_handler(netio_type *netio, netio_handler_type *handler); /* * Retrieve the current time (using gettimeofday(2). */ const struct timespec *netio_current_time(netio_type *netio); /* * Check for events and dispatch them to the handlers. If TIMEOUT is * specified it specifies the maximum time to wait for an event to * arrive. SIGMASK is passed to the underlying pselect(2) call. * Returns the number of non-timeout events dispatched, 0 on timeout, * and -1 on error (with errno set appropriately). */ int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask); #ifdef __cplusplus inline netio_event_types_type operator | (netio_event_types_type lhs, netio_event_types_type rhs) { return (netio_event_types_type) (lhs | rhs); } inline netio_event_types_type operator |= (netio_event_types_type &lhs, netio_event_types_type rhs) { lhs = (netio_event_types_type) (lhs | rhs); return lhs; } #endif /* __cplusplus */ #endif /* _NETIO_H_ */ nsd-4.1.26/LICENSE0000664000175000017500000000273712275161154013050 0ustar wouterwouterCopyright (c) 2001-2006, NLnet Labs. All rights reserved. This software is open source. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the NLNET LABS nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nsd-4.1.26/rdata.c0000664000175000017500000005423213124167704013300 0ustar wouterwouter/* * rdata.c -- RDATA conversion functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "rdata.h" #include "zonec.h" /* Taken from RFC 4398, section 2.1. */ lookup_table_type dns_certificate_types[] = { /* 0 Reserved */ { 1, "PKIX" }, /* X.509 as per PKIX */ { 2, "SPKI" }, /* SPKI cert */ { 3, "PGP" }, /* OpenPGP packet */ { 4, "IPKIX" }, /* The URL of an X.509 data object */ { 5, "ISPKI" }, /* The URL of an SPKI certificate */ { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */ { 7, "ACPKIX" }, /* Attribute Certificate */ { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */ { 253, "URI" }, /* URI private */ { 254, "OID" }, /* OID private */ /* 255 Reserved */ /* 256-65279 Available for IANA assignment */ /* 65280-65534 Experimental */ /* 65535 Reserved */ { 0, NULL } }; /* Taken from RFC 2535, section 7. */ lookup_table_type dns_algorithms[] = { { 1, "RSAMD5" }, /* RFC 2537 */ { 2, "DH" }, /* RFC 2539 */ { 3, "DSA" }, /* RFC 2536 */ { 4, "ECC" }, { 5, "RSASHA1" }, /* RFC 3110 */ { 6, "DSA-NSEC3-SHA1" }, /* RFC 5155 */ { 7, "RSASHA1-NSEC3-SHA1" }, /* RFC 5155 */ { 8, "RSASHA256" }, /* RFC 5702 */ { 10, "RSASHA512" }, /* RFC 5702 */ { 12, "ECC-GOST" }, /* RFC 5933 */ { 13, "ECDSAP256SHA256" }, /* RFC 6605 */ { 14, "ECDSAP384SHA384" }, /* RFC 6605 */ { 15, "ED25519" }, /* RFC 8080 */ { 16, "ED448" }, /* RFC 8080 */ { 252, "INDIRECT" }, { 253, "PRIVATEDNS" }, { 254, "PRIVATEOID" }, { 0, NULL } }; typedef int (*rdata_to_string_type)(buffer_type *output, rdata_atom_type rdata, rr_type *rr); static int rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { buffer_printf(output, "%s", dname_to_string(domain_dname(rdata_atom_domain(rdata)), NULL)); return 1; } static int rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); size_t offset = 0; uint8_t length = data[offset]; size_t i; while (length > 0) { if (offset) /* concat label */ buffer_printf(output, "."); for (i = 1; i <= length; ++i) { uint8_t ch = data[i+offset]; if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') { buffer_printf(output, "\\%c", (char) ch); } else if (!isgraph((unsigned char) ch)) { buffer_printf(output, "\\%03u", (unsigned int) ch); } else if (isprint((unsigned char) ch)) { buffer_printf(output, "%c", (char) ch); } else { buffer_printf(output, "\\%03u", (unsigned int) ch); } } /* next label */ offset = offset+length+1; length = data[offset]; } /* root label */ buffer_printf(output, "."); return 1; } static int rdata_text_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint8_t length = data[0]; size_t i; buffer_printf(output, "\""); for (i = 1; i <= length; ++i) { char ch = (char) data[i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } buffer_printf(output, "\""); return 1; } static int rdata_texts_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t pos = 0; const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; while (pos < length && pos + data[pos] < length) { buffer_printf(output, "\""); for (i = 1; i <= data[pos]; ++i) { char ch = (char) data[pos + i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[pos+i]); } } pos += data[pos]+1; buffer_printf(output, pos < length?"\" ":"\""); } return 1; } static int rdata_long_text_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint16_t length = rdata_atom_size(rdata); size_t i; buffer_printf(output, "\""); for (i = 0; i < length; ++i) { char ch = (char) data[i]; if (isprint((unsigned char)ch)) { if (ch == '"' || ch == '\\') { buffer_printf(output, "\\"); } buffer_printf(output, "%c", ch); } else { buffer_printf(output, "\\%03u", (unsigned) data[i]); } } buffer_printf(output, "\""); return 1; } static int rdata_tag_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { const uint8_t *data = rdata_atom_data(rdata); uint8_t length = data[0]; size_t i; for (i = 1; i <= length; ++i) { char ch = (char) data[i]; if (isdigit((unsigned char)ch) || islower((unsigned char)ch)) buffer_printf(output, "%c", ch); else return 0; } return 1; } static int rdata_byte_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t data = *rdata_atom_data(rdata); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_short_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t data = read_uint16(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_long_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint32_t data = read_uint32(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) data); return 1; } static int rdata_a_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; char str[200]; if (inet_ntop(AF_INET, rdata_atom_data(rdata), str, sizeof(str))) { buffer_printf(output, "%s", str); result = 1; } return result; } static int rdata_aaaa_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; char str[200]; if (inet_ntop(AF_INET6, rdata_atom_data(rdata), str, sizeof(str))) { buffer_printf(output, "%s", str); result = 1; } return result; } static int rdata_ilnp64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint16_t a1 = read_uint16(data); uint16_t a2 = read_uint16(data+2); uint16_t a3 = read_uint16(data+4); uint16_t a4 = read_uint16(data+6); buffer_printf(output, "%.4x:%.4x:%.4x:%.4x", a1, a2, a3, a4); return 1; } static int rdata_eui48_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint8_t a1 = data[0]; uint8_t a2 = data[1]; uint8_t a3 = data[2]; uint8_t a4 = data[3]; uint8_t a5 = data[4]; uint8_t a6 = data[5]; buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", a1, a2, a3, a4, a5, a6); return 1; } static int rdata_eui64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t* data = rdata_atom_data(rdata); uint8_t a1 = data[0]; uint8_t a2 = data[1]; uint8_t a3 = data[2]; uint8_t a4 = data[3]; uint8_t a5 = data[4]; uint8_t a6 = data[5]; uint8_t a7 = data[6]; uint8_t a8 = data[7]; buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", a1, a2, a3, a4, a5, a6, a7, a8); return 1; } static int rdata_rrtype_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t type = read_uint16(rdata_atom_data(rdata)); buffer_printf(output, "%s", rrtype_to_string(type)); return 1; } static int rdata_algorithm_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint8_t id = *rdata_atom_data(rdata); buffer_printf(output, "%u", (unsigned) id); return 1; } static int rdata_certificate_type_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t id = read_uint16(rdata_atom_data(rdata)); lookup_table_type *type = lookup_by_id(dns_certificate_types, id); if (type) { buffer_printf(output, "%s", type->name); } else { buffer_printf(output, "%u", (unsigned) id); } return 1; } static int rdata_period_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint32_t period = read_uint32(rdata_atom_data(rdata)); buffer_printf(output, "%lu", (unsigned long) period); return 1; } static int rdata_time_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; time_t time = (time_t) read_uint32(rdata_atom_data(rdata)); struct tm *tm = gmtime(&time); char buf[15]; if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm)) { buffer_printf(output, "%s", buf); result = 1; } return result; } static int rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { buffer_write(output, "-", 1); return 1; } size -= 1; /* remove length byte from count */ buffer_reserve(output, size * 2 + 1); length = b32_ntop(rdata_atom_data(rdata)+1, size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { /* single zero represents empty buffer */ buffer_write(output, "0", 1); return 1; } buffer_reserve(output, size * 2 + 1); length = b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; } static void hex_to_string(buffer_type *output, const uint8_t *data, size_t size) { static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; size_t i; buffer_reserve(output, size * 2); for (i = 0; i < size; ++i) { uint8_t octet = *data++; buffer_write_u8(output, hexdigits[octet >> 4]); buffer_write_u8(output, hexdigits[octet & 0x0f]); } } static int rdata_hex_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { if(rdata_atom_size(rdata) == 0) { /* single zero represents empty buffer, such as CDS deletes */ buffer_printf(output, "0"); } else { hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata)); } return 1; } static int rdata_hexlen_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { if(rdata_atom_size(rdata) <= 1) { /* NSEC3 salt hex can be empty */ buffer_printf(output, "-"); return 1; } hex_to_string(output, rdata_atom_data(rdata)+1, rdata_atom_size(rdata)-1); return 1; } static int rdata_nsap_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { buffer_printf(output, "0x"); hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata)); return 1; } static int rdata_apl_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 4)) { uint16_t address_family = buffer_read_u16(&packet); uint8_t prefix = buffer_read_u8(&packet); uint8_t length = buffer_read_u8(&packet); int negated = length & APL_NEGATION_MASK; int af = -1; length &= APL_LENGTH_MASK; switch (address_family) { case 1: af = AF_INET; break; case 2: af = AF_INET6; break; } if (af != -1 && buffer_available(&packet, length)) { char text_address[1000]; uint8_t address[128]; memset(address, 0, sizeof(address)); buffer_read(&packet, address, length); if (inet_ntop(af, address, text_address, sizeof(text_address))) { buffer_printf(output, "%s%d:%s/%d", negated ? "!" : "", (int) address_family, text_address, (int) prefix); result = 1; } } } return result; } static int rdata_services_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 1)) { uint8_t protocol_number = buffer_read_u8(&packet); ssize_t bitmap_size = buffer_remaining(&packet); uint8_t *bitmap = buffer_current(&packet); struct protoent *proto = getprotobynumber(protocol_number); if (proto) { int i; buffer_printf(output, "%s", proto->p_name); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { struct servent *service = getservbyport((int)htons(i), proto->p_name); if (service) { buffer_printf(output, " %s", service->s_name); } else { buffer_printf(output, " %d", i); } } } buffer_skip(&packet, bitmap_size); result = 1; } } return result; } static int rdata_ipsecgateway_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr) { int gateway_type = rdata_atom_data(rr->rdatas[1])[0]; switch(gateway_type) { case IPSECKEY_NOGATEWAY: buffer_printf(output, "."); break; case IPSECKEY_IP4: rdata_a_to_string(output, rdata, rr); break; case IPSECKEY_IP6: rdata_aaaa_to_string(output, rdata, rr); break; case IPSECKEY_DNAME: { region_type* temp = region_create(xalloc, free); const dname_type* d = dname_make(temp, rdata_atom_data(rdata), 0); if(!d) { region_destroy(temp); return 0; } buffer_printf(output, "%s", dname_to_string(d, NULL)); region_destroy(temp); } break; default: return 0; } return 1; } static int rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t i; uint8_t *bitmap = rdata_atom_data(rdata); size_t bitmap_size = rdata_atom_size(rdata); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s ", rrtype_to_string(i)); } } buffer_skip(output, -1); return 1; } static int rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t saved_position = buffer_position(output); buffer_type packet; int insert_space = 0; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); while (buffer_available(&packet, 2)) { uint8_t window = buffer_read_u8(&packet); uint8_t bitmap_size = buffer_read_u8(&packet); uint8_t *bitmap = buffer_current(&packet); int i; if (!buffer_available(&packet, bitmap_size)) { buffer_set_position(output, saved_position); return 0; } for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s%s", insert_space ? " " : "", rrtype_to_string( window * 256 + i)); insert_space = 1; } } buffer_skip(&packet, bitmap_size); } return 1; } static int rdata_loc_to_string(buffer_type *ATTR_UNUSED(output), rdata_atom_type ATTR_UNUSED(rdata), rr_type* ATTR_UNUSED(rr)) { /* * Returning 0 forces the record to be printed in unknown * format. */ return 0; } static int rdata_unknown_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { uint16_t size = rdata_atom_size(rdata); buffer_printf(output, "\\# %lu ", (unsigned long) size); hex_to_string(output, rdata_atom_data(rdata), size); return 1; } static rdata_to_string_type rdata_to_string_table[RDATA_ZF_UNKNOWN + 1] = { rdata_dname_to_string, rdata_dns_name_to_string, rdata_text_to_string, rdata_texts_to_string, rdata_byte_to_string, rdata_short_to_string, rdata_long_to_string, rdata_a_to_string, rdata_aaaa_to_string, rdata_rrtype_to_string, rdata_algorithm_to_string, rdata_certificate_type_to_string, rdata_period_to_string, rdata_time_to_string, rdata_base64_to_string, rdata_base32_to_string, rdata_hex_to_string, rdata_hexlen_to_string, rdata_nsap_to_string, rdata_apl_to_string, rdata_ipsecgateway_to_string, rdata_services_to_string, rdata_nxt_to_string, rdata_nsec_to_string, rdata_loc_to_string, rdata_ilnp64_to_string, rdata_eui48_to_string, rdata_eui64_to_string, rdata_long_text_to_string, rdata_tag_to_string, rdata_unknown_to_string }; int rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type, rdata_atom_type rdata, rr_type* record) { return rdata_to_string_table[type](output, rdata, record); } ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t data_size, buffer_type *packet, rdata_atom_type **rdatas) { size_t end = buffer_position(packet) + data_size; size_t i; rdata_atom_type temp_rdatas[MAXRDATALEN]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); region_type *temp_region; assert(descriptor->maximum <= MAXRDATALEN); if (!buffer_available(packet, data_size)) { return -1; } temp_region = region_create(xalloc, free); for (i = 0; i < descriptor->maximum; ++i) { int is_domain = 0; int is_normalized = 0; int is_wirestore = 0; size_t length = 0; int required = i < descriptor->minimum; switch (rdata_atom_wireformat_type(rrtype, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: is_domain = 1; is_normalized = 1; break; case RDATA_WF_LITERAL_DNAME: is_domain = 1; is_wirestore = 1; break; case RDATA_WF_BYTE: length = sizeof(uint8_t); break; case RDATA_WF_SHORT: length = sizeof(uint16_t); break; case RDATA_WF_LONG: length = sizeof(uint32_t); break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: length = end - buffer_position(packet); break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: /* Length is stored in the first byte. */ length = 1; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[length - 1]; } break; case RDATA_WF_A: length = sizeof(in_addr_t); break; case RDATA_WF_AAAA: length = IP6ADDRLEN; break; case RDATA_WF_ILNP64: length = IP6ADDRLEN/2; break; case RDATA_WF_EUI48: length = EUI48ADDRLEN; break; case RDATA_WF_EUI64: length = EUI64ADDRLEN; break; case RDATA_WF_BINARY: /* Remaining RDATA is binary. */ length = end - buffer_position(packet); break; case RDATA_WF_APL: length = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if (buffer_position(packet) + length <= end) { /* Mask out negation bit. */ length += (buffer_current(packet)[length - 1] & APL_LENGTH_MASK); } break; case RDATA_WF_IPSECGATEWAY: switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ { default: case IPSECKEY_NOGATEWAY: length = 0; break; case IPSECKEY_IP4: length = IP4ADDRLEN; break; case IPSECKEY_IP6: length = IP6ADDRLEN; break; case IPSECKEY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; } if (is_domain) { const dname_type *dname; if (!required && buffer_position(packet) == end) { break; } dname = dname_make_from_packet( temp_region, packet, 1, is_normalized); if (!dname || buffer_position(packet) > end) { /* Error in domain name. */ region_destroy(temp_region); return -1; } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + ((size_t)dname->name_size)); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); } else { temp_rdatas[i].domain = domain_table_insert(owners, dname); temp_rdatas[i].domain->usage ++; } } else { if (buffer_position(packet) + length > end) { if (required) { /* Truncated RDATA. */ region_destroy(temp_region); return -1; } else { break; } } if (!required && buffer_position(packet) == end) { break; } temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + length); temp_rdatas[i].data[0] = length; buffer_read(packet, temp_rdatas[i].data + 1, length); } } if (buffer_position(packet) < end) { /* Trailing garbage. */ region_destroy(temp_region); return -1; } *rdatas = (rdata_atom_type *) region_alloc_array_init( region, temp_rdatas, i, sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; } size_t rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas) { size_t result = 0; size_t i; for (i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(descriptor->type, i)) { result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size; } else { result += rdata_atom_size(rdatas[i]); } } return result; } int rdata_atoms_to_unknown_string(buffer_type *output, rrtype_descriptor_type *descriptor, size_t rdata_count, rdata_atom_type *rdatas) { size_t i; size_t size = rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas); buffer_printf(output, " \\# %lu ", (unsigned long) size); for (i = 0; i < rdata_count; ++i) { if (rdata_atom_is_domain(descriptor->type, i)) { const dname_type *dname = domain_dname(rdata_atom_domain(rdatas[i])); hex_to_string( output, dname_name(dname), dname->name_size); } else { hex_to_string(output, rdata_atom_data(rdatas[i]), rdata_atom_size(rdatas[i])); } } return 1; } int print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor, rr_type *record) { size_t i; size_t saved_position = buffer_position(output); for (i = 0; i < record->rdata_count; ++i) { if (i == 0) { buffer_printf(output, "\t"); } else if (descriptor->type == TYPE_SOA && i == 2) { buffer_printf(output, " (\n\t\t"); } else { buffer_printf(output, " "); } if (!rdata_atom_to_string( output, (rdata_zoneformat_type) descriptor->zoneformat[i], record->rdatas[i], record)) { buffer_set_position(output, saved_position); return 0; } } if (descriptor->type == TYPE_SOA) { buffer_printf(output, " )"); } return 1; } nsd-4.1.26/difffile.c0000664000175000017500000017123513334272434013760 0ustar wouterwouter/* * difffile.c - DIFF file handling source code. Read and write diff files. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include "difffile.h" #include "xfrd-disk.h" #include "util.h" #include "packet.h" #include "rdata.h" #include "udb.h" #include "udbzone.h" #include "nsec3.h" #include "nsd.h" #include "rrl.h" static int write_64(FILE *out, uint64_t val) { return write_data(out, &val, sizeof(val)); } static int write_32(FILE *out, uint32_t val) { val = htonl(val); return write_data(out, &val, sizeof(val)); } static int write_8(FILE *out, uint8_t val) { return write_data(out, &val, sizeof(val)); } static int write_str(FILE *out, const char* str) { uint32_t len = strlen(str); if(!write_32(out, len)) return 0; return write_data(out, str, len); } void diff_write_packet(const char* zone, const char* pat, uint32_t old_serial, uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len, struct nsd* nsd, uint64_t filenumber) { FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w"); if(!df) { log_msg(LOG_ERR, "could not open transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); return; } /* if first part, first write the header */ if(seq_nr == 0) { struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { log_msg(LOG_ERR, "could not get timestamp for %s: %s", zone, strerror(errno)); } if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, 0) /* notcommitted(yet) */ || !write_32(df, 0) /* numberofparts when done */ || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_32(df, old_serial) || !write_32(df, new_serial) || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_str(df, zone) || !write_str(df, pat)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } } if(!write_32(df, DIFF_PART_XXFR) || !write_32(df, len) || !write_data(df, data, len) || !write_32(df, len)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); } fclose(df); } void diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial, uint32_t num_parts, uint8_t commit, const char* log_str, struct nsd* nsd, uint64_t filenumber) { struct timeval tv; FILE* df; if (gettimeofday(&tv, NULL) != 0) { log_msg(LOG_ERR, "could not set timestamp for %s: %s", zone, strerror(errno)); } /* overwrite the first part of the file with 'committed = 1', * as well as the end_time and number of parts. * also write old_serial and new_serial, so that a bad file mixup * will result in unusable serial numbers. */ df = xfrd_open_xfrfile(nsd, filenumber, "r+"); if(!df) { log_msg(LOG_ERR, "could not open transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); return; } if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, commit) /* committed */ || !write_32(df, num_parts) || !write_64(df, (uint64_t) tv.tv_sec) || !write_32(df, (uint32_t) tv.tv_usec) || !write_32(df, old_serial) || !write_32(df, new_serial)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } /* append the log_str to the end of the file */ if(fseek(df, 0, SEEK_END) == -1) { log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } if(!write_str(df, log_str)) { log_msg(LOG_ERR, "could not write transfer %s file %lld: %s", zone, (long long)filenumber, strerror(errno)); fclose(df); return; } fflush(df); fclose(df); } int diff_read_64(FILE *in, uint64_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } int diff_read_32(FILE *in, uint32_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { *result = ntohl(*result); return 1; } else { return 0; } } int diff_read_8(FILE *in, uint8_t* result) { if (fread(result, sizeof(*result), 1, in) == 1) { return 1; } else { return 0; } } int diff_read_str(FILE* in, char* buf, size_t len) { uint32_t disklen; if(!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; } static void add_rdata_to_recyclebin(namedb_type* db, rr_type* rr) { /* add rdatas to recycle bin. */ size_t i; for(i=0; irdata_count; i++) { if(!rdata_atom_is_domain(rr->type, i)) region_recycle(db->region, rr->rdatas[i].data, rdata_atom_size(rr->rdatas[i]) + sizeof(uint16_t)); } region_recycle(db->region, rr->rdatas, sizeof(rdata_atom_type)*rr->rdata_count); } /* this routine determines if below a domain there exist names with * data (is_existing) or no names below the domain have data. */ static int has_data_below(domain_type* top) { domain_type* d = top; assert(d != NULL); /* in the canonical ordering subdomains are after this name */ d = domain_next(d); while(d != NULL && domain_is_subdomain(d, top)) { if(d->is_existing) return 1; d = domain_next(d); } return 0; } /** check if domain with 0 rrsets has become empty (nonexist) */ static domain_type* rrset_zero_nonexist_check(domain_type* domain, domain_type* ce) { /* is the node now an empty node (completely deleted) */ if(domain->rrsets == 0) { /* if there is no data below it, it becomes non existing. also empty nonterminals above it become nonexisting */ /* check for data below this node. */ if(!has_data_below(domain)) { /* nonexist this domain and all parent empty nonterminals */ domain_type* p = domain; while(p != NULL && p->rrsets == 0) { if(p == ce || has_data_below(p)) return p; p->is_existing = 0; /* fixup wildcard child of parent */ if(p->parent && p->parent->wildcard_child_closest_match == p) p->parent->wildcard_child_closest_match = domain_previous_existing_child(p); p = p->parent; } } } return NULL; } /** remove rrset. Adjusts zone params. Does not remove domain */ static void rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset) { int i; /* find previous */ rrset_type** pp = &domain->rrsets; while(*pp && *pp != rrset) { pp = &( (*pp)->next ); } if(!*pp) { /* rrset does not exist for domain */ return; } *pp = rrset->next; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s", domain_to_string(domain), rrtype_to_string(rrset_rrtype(rrset)))); /* is this a SOA rrset ? */ if(rrset->zone->soa_rrset == rrset) { rrset->zone->soa_rrset = 0; } if(rrset->zone->ns_rrset == rrset) { rrset->zone->ns_rrset = 0; } if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) { for (i = 0; i < rrset->rr_count; ++i) { if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) { rrset->zone->is_secure = 0; break; } } } /* recycle the memory space of the rrset */ for (i = 0; i < rrset->rr_count; ++i) add_rdata_to_recyclebin(db, &rrset->rrs[i]); region_recycle(db->region, rrset->rrs, sizeof(rr_type) * rrset->rr_count); rrset->rr_count = 0; region_recycle(db->region, rrset, sizeof(rrset_type)); } static int rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type, int* rdnum, char** reason) { int k, start, end; start = 0; end = num; /** * SOA RDATA comparisons in XFR are more lenient, * only serial rdata is checked. **/ if (type == TYPE_SOA) { start = 2; end = 3; } for(k = start; k < end; k++) { if(rdata_atom_is_domain(type, k)) { if(dname_compare(domain_dname(a[k].domain), domain_dname(b[k].domain))!=0) { *rdnum = k; *reason = "dname data"; return 0; } } else if(rdata_atom_is_literal_domain(type, k)) { /* literal dname, but compare case insensitive */ if(a[k].data[0] != b[k].data[0]) { *rdnum = k; *reason = "literal dname len"; return 0; /* uncompressed len must be equal*/ } if(!dname_equal_nocase((uint8_t*)(a[k].data+1), (uint8_t*)(b[k].data+1), a[k].data[0])) { *rdnum = k; *reason = "literal dname data"; return 0; } } else { /* check length */ if(a[k].data[0] != b[k].data[0]) { *rdnum = k; *reason = "rdata len"; return 0; } /* check data */ if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) { *rdnum = k; *reason = "rdata data"; return 0; } } } return 1; } static void debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass, rdata_atom_type *rdatas, ssize_t rdata_num) { int i, rd; char* reason = ""; for(i=0; i < rrset->rr_count; ++i) { if (rrset->rrs[i].type != type) { log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match " "RR num %d type %s", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), i, rrtype_to_string(rrset->rrs[i].type)); } if (rrset->rrs[i].klass != klass) { log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d " "does not match RR num %d class %d", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), klass, i, rrset->rrs[i].klass); } if (rrset->rrs[i].rdata_count != rdata_num) { log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u " "does not match RR num %d rdlen %d", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), (unsigned) rdata_num, i, (unsigned) rrset->rrs[i].rdata_count); } if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type, &rd, &reason)) { log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element " "%d differs from RR num %d rdata (%s)", dname_to_string(domain_dname(rrset->rrs[i].owner),0), rrtype_to_string(type), rd, i, reason); } } } static int find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass, rdata_atom_type *rdatas, ssize_t rdata_num, int add) { int i, rd; char* reason; for(i=0; i < rrset->rr_count; ++i) { if(rrset->rrs[i].type == type && rrset->rrs[i].klass == klass && rrset->rrs[i].rdata_count == rdata_num && rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type, &rd, &reason)) { return i; } } /* this is odd. Log why rr cannot be found. */ if (!add) { debug_find_rr_num(rrset, type, klass, rdatas, rdata_num); } return -1; } #ifdef NSEC3 /* see if nsec3 deletion triggers need action */ static void nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, udb_ptr* udbz) { /* the RR has not actually been deleted yet, so we can inspect it */ if(!zone->nsec3_param) return; /* see if the domain was an NSEC3-domain in the chain, but no longer */ if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 && rr->owner->nsec3->nsec3_node.key && nsec3_rr_uses_params(rr, zone) && nsec3_in_chain_count(rr->owner, zone) <= 1) { domain_type* prev = nsec3_chain_find_prev(zone, rr->owner); /* remove from prehash because no longer an NSEC3 domain */ if(domain_is_prehash(db->domains, rr->owner)) prehash_del(db->domains, rr->owner); /* fixup the last in the zone */ if(rr->owner == zone->nsec3_last) zone->nsec3_last = prev; /* unlink from the nsec3tree */ zone_del_domain_in_hash_tree(zone->nsec3tree, &rr->owner->nsec3->nsec3_node); /* add previous NSEC3 to the prehash list */ if(prev && prev != rr->owner) prehash_add(db->domains, prev); else nsec3_clear_precompile(db, zone); /* this domain becomes ordinary data domain: done later */ } /* see if the rr was NSEC3PARAM that we were using */ else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) { /* clear trees, wipe hashes, wipe precompile */ nsec3_clear_precompile(db, zone); /* pick up new nsec3param (from udb, or avoid deleted rr) */ nsec3_find_zone_param(db, zone, udbz, rr, 0); /* if no more NSEC3, done */ if(!zone->nsec3_param) return; nsec3_precompile_newparam(db, zone); } } /* see if nsec3 prehash can be removed with new rrset content */ static void nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone) { /* deletion of rrset already done, we can check if conditions apply */ /* 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_wc && domain->nsec3->hash_wc->hash.node.key && !nsec3_condition_hash(domain, zone)) { /* remove precompile */ domain->nsec3->nsec3_cover = NULL; domain->nsec3->nsec3_wcard_child_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_wc->hash.node); zone_del_domain_in_hash_tree(zone->wchashtree, &domain->nsec3->hash_wc->wc.node); } if(domain != zone->apex && domain->nsec3 && 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_cover = NULL; domain->nsec3->nsec3_ds_parent_is_exact = 0; /* remove it from the hash tree */ zone_del_domain_in_hash_tree(zone->dshashtree, &domain->nsec3->ds_parent_hash->node); } } /* see if domain needs to get precompiled info */ static void nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain, zone_type* zone) { if(!zone->nsec3_param) return; 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->ds_parent_hash || !domain->nsec3->ds_parent_hash->node.key) && nsec3_condition_dshash(domain, zone)) { nsec3_precompile_domain_ds(db, domain, zone); } } /* see if nsec3 rrset-deletion triggers need action */ static void nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone, uint16_t type) { if(!zone->nsec3_param) return; nsec3_rrsets_changed_remove_prehash(domain, zone); /* for type nsec3, or a delegation, the domain may have become a * 'normal' domain with its remaining data now */ if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS) nsec3_rrsets_changed_add_prehash(db, domain, zone); /* for type DNAME or a delegation, obscured data may be revealed */ if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) { /* walk over subdomains and check them each */ domain_type *d; for(d=domain_next(domain); d && domain_is_subdomain(d, domain); d=domain_next(d)) { nsec3_rrsets_changed_add_prehash(db, d, zone); } } } /* see if nsec3 addition triggers need action */ static void nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, udb_ptr* udbz) { /* the RR has been added in full, also to UDB (and thus NSEC3PARAM * in the udb has been adjusted) */ if(zone->nsec3_param && rr->type == TYPE_NSEC3 && (!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key) && nsec3_rr_uses_params(rr, zone)) { /* added NSEC3 into the chain */ nsec3_precompile_nsec3rr(db, rr->owner, zone); /* the domain has become an NSEC3-domain, if it was precompiled * previously, remove that, neatly done in routine above */ nsec3_rrsets_changed_remove_prehash(rr->owner, zone); /* set this NSEC3 to prehash */ prehash_add(db->domains, rr->owner); } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) { /* see if this means NSEC3 chain can be used */ nsec3_find_zone_param(db, zone, udbz, NULL, 0); if(!zone->nsec3_param) return; nsec3_zone_trees_create(db->region, zone); nsec3_precompile_newparam(db, zone); } } /* see if nsec3 rrset-addition triggers need action */ static void nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone, uint16_t type) { /* the rrset has been added so we can inspect it */ if(!zone->nsec3_param) return; /* because the rrset is added we can check conditions easily. * check if domain needs to become precompiled now */ nsec3_rrsets_changed_add_prehash(db, domain, zone); /* if a delegation, it changes from normal name to unhashed referral */ if(type == TYPE_NS || type == TYPE_DS) { nsec3_rrsets_changed_remove_prehash(domain, zone); } /* if delegation or DNAME added, then some RRs may get obscured */ if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) { /* walk over subdomains and check them each */ domain_type *d; for(d=domain_next(domain); d && domain_is_subdomain(d, domain); d=domain_next(d)) { nsec3_rrsets_changed_remove_prehash(d, zone); } } } #endif /* NSEC3 */ /* fixup usage lower for domain names in the rdata */ static void rr_lower_usage(namedb_type* db, rr_type* rr) { unsigned i; for(i=0; irdata_count; i++) { if(rdata_atom_is_domain(rr->type, i)) { assert(rdata_atom_domain(rr->rdatas[i])->usage > 0); rdata_atom_domain(rr->rdatas[i])->usage --; if(rdata_atom_domain(rr->rdatas[i])->usage == 0) domain_table_deldomain(db, rdata_atom_domain(rr->rdatas[i])); } } } static void rrset_lower_usage(namedb_type* db, rrset_type* rrset) { unsigned i; for(i=0; irr_count; i++) rr_lower_usage(db, &rrset->rrs[i]); } int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, region_type* temp_region, udb_ptr* udbz, int* softfail) { domain_type *domain; rrset_type *rrset; domain = domain_table_find(db->domains, dname); if(!domain) { log_msg(LOG_WARNING, "diff: domain %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); *softfail = 1; return 1; /* not fatal error */ } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { log_msg(LOG_WARNING, "diff: rrset %s does not exist", dname_to_string(dname,0)); buffer_skip(packet, rdatalen); *softfail = 1; return 1; /* not fatal error */ } else { /* find the RR in the rrset */ domain_table_type *temptable; rdata_atom_type *rdatas; ssize_t rdata_num; int rrnum; temptable = domain_table_create(temp_region); /* This will ensure that the dnames in rdata are * normalized, conform RFC 4035, section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( temp_region, temptable, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0); if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex && rrset->rr_count != 0) rrnum = 0; /* replace existing SOA if no match */ if(rrnum == -1) { log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist", dname_to_string(dname,0), rrtype_to_string(type)); *softfail = 1; return 1; /* not fatal error */ } /* delete the normalized RR from the udb */ if(db->udb) udb_del_rr(db->udb, udbz, &rrset->rrs[rrnum]); #ifdef NSEC3 /* process triggers for RR deletions */ nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone, udbz); #endif /* lower usage (possibly deleting other domains, and thus * invalidating the current RR's domain pointers) */ rr_lower_usage(db, &rrset->rrs[rrnum]); if(rrset->rr_count == 1) { /* delete entire rrset */ rrset_delete(db, domain, rrset); /* check if domain is now nonexisting (or parents) */ rrset_zero_nonexist_check(domain, NULL); #ifdef NSEC3 /* cleanup nsec3 */ nsec3_delete_rrset_trigger(db, domain, zone, type); #endif /* see if the domain can be deleted (and inspect parents) */ domain_table_deldomain(db, domain); } else { /* swap out the bad RR and decrease the count */ rr_type* rrs_orig = rrset->rrs; add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]); if(rrnum < rrset->rr_count-1) rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1]; memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type)); /* realloc the rrs array one smaller */ rrset->rrs = region_alloc_array_init(db->region, rrs_orig, (rrset->rr_count-1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } region_recycle(db->region, rrs_orig, sizeof(rr_type) * rrset->rr_count); #ifdef NSEC3 if(type == TYPE_NSEC3PARAM && zone->nsec3_param) { /* fixup nsec3_param pointer to same RR */ assert(zone->nsec3_param >= rrs_orig && zone->nsec3_param <= rrs_orig+rrset->rr_count); /* last moved to rrnum, others at same index*/ if(zone->nsec3_param == &rrs_orig[ rrset->rr_count-1]) zone->nsec3_param = &rrset->rrs[rrnum]; else zone->nsec3_param = (void*)zone->nsec3_param -(void*)rrs_orig + (void*)rrset->rrs; } #endif /* NSEC3 */ rrset->rr_count --; #ifdef NSEC3 /* for type nsec3, the domain may have become a * 'normal' domain with its remaining data now */ if(type == TYPE_NSEC3) nsec3_rrsets_changed_add_prehash(db, domain, zone); #endif /* NSEC3 */ } } return 1; } int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, udb_ptr* udbz, int* softfail) { domain_type* domain; rrset_type* rrset; rdata_atom_type *rdatas; rr_type *rrs_old; ssize_t rdata_num; int rrnum; #ifdef NSEC3 int rrset_added = 0; #endif domain = domain_table_find(db->domains, dname); if(!domain) { /* create the domain */ domain = domain_table_insert(db->domains, dname); } rrset = domain_find_rrset(domain, zone, type); if(!rrset) { /* create the rrset */ rrset = region_alloc(db->region, sizeof(rrset_type)); if(!rrset) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } rrset->zone = zone; rrset->rrs = 0; rrset->rr_count = 0; domain_add_rrset(domain, rrset); #ifdef NSEC3 rrset_added = 1; #endif } /* dnames in rdata are normalized, conform RFC 4035, * Section 6.2 */ rdata_num = rdata_wireformat_to_rdata_atoms( db->region, db->domains, type, rdatalen, packet, &rdatas); if(rdata_num == -1) { log_msg(LOG_ERR, "diff: bad rdata for %s", dname_to_string(dname,0)); return 0; } rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1); if(rrnum != -1) { DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists", dname_to_string(dname,0), rrtype_to_string(type))); /* ignore already existing RR: lenient accepting of messages */ *softfail = 1; return 1; } if(rrset->rr_count == 65535) { log_msg(LOG_ERR, "diff: too many RRs at %s", dname_to_string(dname,0)); return 0; } /* re-alloc the rrs and add the new */ rrs_old = rrset->rrs; rrset->rrs = region_alloc_array(db->region, (rrset->rr_count+1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); } if(rrs_old) memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type)); region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count); rrset->rr_count ++; rrset->rrs[rrset->rr_count - 1].owner = domain; rrset->rrs[rrset->rr_count - 1].rdatas = rdatas; rrset->rrs[rrset->rr_count - 1].ttl = ttl; rrset->rrs[rrset->rr_count - 1].type = type; rrset->rrs[rrset->rr_count - 1].klass = klass; rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num; /* see if it is a SOA */ if(domain == zone->apex) { apex_rrset_checks(db, rrset, domain); #ifdef NSEC3 if(type == TYPE_NSEC3PARAM && zone->nsec3_param) { /* the pointer just changed, fix it up to point * to the same record */ assert(zone->nsec3_param >= rrs_old && zone->nsec3_param < rrs_old+rrset->rr_count); /* in this order to make sure no overflow/underflow*/ zone->nsec3_param = (void*)zone->nsec3_param - (void*)rrs_old + (void*)rrset->rrs; } #endif /* NSEC3 */ } /* write the just-normalized RR to the udb */ if(db->udb) { if(!udb_write_rr(db->udb, udbz, &rrset->rrs[rrset->rr_count - 1])) { log_msg(LOG_ERR, "could not add RR to nsd.db, disk-space?"); return 0; } } #ifdef NSEC3 if(rrset_added) { domain_type* p = domain->parent; nsec3_add_rrset_trigger(db, domain, zone, type); /* go up and process (possibly created) empty nonterminals, * until we hit the apex or root */ while(p && p->rrsets == NULL && !p->is_apex) { nsec3_rrsets_changed_add_prehash(db, p, zone); p = p->parent; } } nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone, udbz); #endif /* NSEC3 */ return 1; } static zone_type* find_or_create_zone(namedb_type* db, const dname_type* zone_name, struct nsd_options* opt, const char* zstr, const char* patname) { zone_type* zone; struct zone_options* zopt; zone = namedb_find_zone(db, zone_name); if(zone) { return zone; } zopt = zone_options_find(opt, zone_name); if(!zopt) { /* if _implicit_ then insert as _part_of_config */ if(strncmp(patname, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)) == 0) { zopt = zone_options_create(opt->region); if(!zopt) return 0; zopt->part_of_config = 1; zopt->name = region_strdup(opt->region, zstr); zopt->pattern = pattern_options_find(opt, patname); if(!zopt->name || !zopt->pattern) return 0; if(!nsd_options_insert_zone(opt, zopt)) { log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " "pattern %s", zstr, patname); } } else { /* create zone : presumably already added to zonelist * by xfrd, who wrote the AXFR or IXFR to disk, so we only * need to add it to our config. * This process does not need linesize and offset zonelist */ zopt = zone_list_zone_insert(opt, zstr, patname, 0, 0); if(!zopt) return 0; } } zone = namedb_zone_create(db, zone_name, zopt); return zone; } void delete_zone_rrs(namedb_type* db, zone_type* zone) { rrset_type *rrset; domain_type *domain = zone->apex, *next; int nonexist_check = 0; /* go through entire tree below the zone apex (incl subzones) */ while(domain && domain_is_subdomain(domain, zone->apex)) { DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s", domain_to_string(domain))); /* delete all rrsets of the zone */ while((rrset = domain_find_any_rrset(domain, zone))) { /* lower usage can delete other domains */ rrset_lower_usage(db, rrset); /* rrset del does not delete our domain(yet) */ rrset_delete(db, domain, rrset); /* no rrset_zero_nonexist_check, do that later */ if(domain->rrsets == 0) nonexist_check = 1; } /* the delete upcoming could delete parents, but nothing next * or after the domain so store next ptr */ next = domain_next(domain); /* see if the domain can be deleted (and inspect parents) */ domain_table_deldomain(db, domain); domain = next; } /* check if data deletions have created nonexisting domain entries, * but after deleting domains so the checks are faster */ if(nonexist_check) { domain_type* ce = NULL; /* for speeding up has_data_below */ DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check")); domain = zone->apex; while(domain && domain_is_subdomain(domain, zone->apex)) { /* the interesting domains should be existing==1 * and rrsets==0, speeding up out processing of * sub-zones, since we only spuriously check empty * nonterminals */ if(domain->is_existing) ce = rrset_zero_nonexist_check(domain, ce); domain = domain_next(domain); } } DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes", (unsigned long) region_get_recycle_size(db->region))); #ifndef NDEBUG if(nsd_debug_level >= 2) region_log_stats(db->region); #endif assert(zone->soa_rrset == 0); /* keep zone->soa_nx_rrset alloced: it is reused */ assert(zone->ns_rrset == 0); assert(zone->is_secure == 0); } /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ static int apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, struct nsd_options* opt, uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes, int* softfail) { uint32_t msglen, checklen, pkttype; int qcount, ancount, counter; buffer_type* packet; region_type* region; int i; uint16_t rrlen; const dname_type *dname_zone, *dname; zone_type* zone_db; /* note that errors could not really happen due to format of the * packet since xfrd has checked all dnames and RRs before commit, * this is why the errors are fatal (exit process), it must be * something internal or a bad disk or something. */ /* read ixfr packet RRs and apply to in memory db */ if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) { log_msg(LOG_ERR, "could not read type or wrong type"); return 0; } if(!diff_read_32(in, &msglen)) { log_msg(LOG_ERR, "could not read len"); return 0; } if(msglen < QHEADERSZ) { log_msg(LOG_ERR, "msg too short"); return 0; } region = region_create(xalloc, free); if(!region) { log_msg(LOG_ERR, "out of memory"); return 0; } packet = buffer_create(region, QIOBUFSZ); if(msglen > QIOBUFSZ) { log_msg(LOG_ERR, "msg too long"); region_destroy(region); return 0; } buffer_clear(packet); if(fread(buffer_begin(packet), msglen, 1, in) != 1) { log_msg(LOG_ERR, "short fread: %s", strerror(errno)); region_destroy(region); return 0; } buffer_set_limit(packet, msglen); /* see if check on data fails: checks that we are not reading * random garbage */ if(!diff_read_32(in, &checklen) || checklen != msglen) { log_msg(LOG_ERR, "transfer part has incorrect checkvalue"); return 0; } *bytes += msglen; dname_zone = dname_parse(region, zone); zone_db = find_or_create_zone(db, dname_zone, opt, zone, patname); if(!zone_db) { log_msg(LOG_ERR, "could not create zone %s %s", zone, patname); region_destroy(region); return 0; } *zone_res = zone_db; /* only answer section is really used, question, additional and authority section RRs are skipped */ qcount = QDCOUNT(packet); ancount = ANCOUNT(packet); buffer_skip(packet, QHEADERSZ); /* skip queries */ for(i=0; insec3_param = NULL; #endif delete_zone_rrs(db, zone_db); if(db->udb) udb_zone_clear(db->udb, udbz); /* add everything else (incl end SOA) */ *delete_mode = 0; *is_axfr = 1; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(*rr_count == 1 && type == TYPE_SOA) { /* if the serial no of the SOA equals the serialno, then AXFR */ size_t bufpos = buffer_position(packet); uint32_t thisserial; if(!packet_skip_dname(packet) || !packet_skip_dname(packet) || buffer_remaining(packet) < sizeof(uint32_t)*5) { log_msg(LOG_ERR, "bad xfr SOA RR formerr."); region_destroy(region); return 0; } thisserial = buffer_read_u32(packet); if(thisserial == serialno) { /* AXFR */ #ifdef NSEC3 nsec3_clear_precompile(db, zone_db); zone_db->nsec3_param = NULL; #endif delete_zone_rrs(db, zone_db); if(db->udb) udb_zone_clear(db->udb, udbz); *delete_mode = 0; *is_axfr = 1; } /* must have stuff in memory for a successful IXFR, * the serial number of the SOA has been checked * previously (by check_for_bad_serial) if it exists */ if(!*is_axfr && !domain_find_rrset(zone_db->apex, zone_db, TYPE_SOA)) { log_msg(LOG_ERR, "%s SOA serial %u is not " "in memory, skip IXFR", zone, serialno); region_destroy(region); /* break out and stop the IXFR, ignore it */ return 2; } buffer_set_position(packet, bufpos); } if(type == TYPE_SOA && !*is_axfr) { /* switch from delete-part to add-part and back again, just before soa - so it gets deleted and added too */ /* this means we switch to delete mode for the final SOA */ *delete_mode = !*delete_mode; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } if(type == TYPE_TSIG || type == TYPE_OPT) { /* ignore pseudo RRs */ buffer_skip(packet, rrlen); continue; } DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", *delete_mode?"del":"add", dname_to_string(dname,0), rrtype_to_string(type))); if(*delete_mode) { /* delete this rr */ if(!*is_axfr && type == TYPE_SOA && counter==ancount-1 && seq_nr == seq_total-1) { continue; /* do not delete final SOA RR for IXFR */ } if(!delete_RR(db, dname, type, klass, packet, rrlen, zone_db, region, udbz, softfail)) { region_destroy(region); return 0; } } else { /* add this rr */ if(!add_RR(db, dname, type, klass, ttl, packet, rrlen, zone_db, udbz, softfail)) { region_destroy(region); return 0; } } } region_destroy(region); return 1; } static int check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) { /* see if serial OK with in-memory serial */ domain_type* domain; region_type* region = region_create(xalloc, free); const dname_type* zone_name = dname_parse(region, zone_str); zone_type* zone = 0; domain = domain_table_find(db->domains, zone_name); if(domain) zone = domain_find_zone(db, domain); if(zone && zone->apex == domain && zone->soa_rrset && old_serial) { uint32_t memserial; memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); if(old_serial != ntohl(memserial)) { region_destroy(region); return 1; } } region_destroy(region); return 0; } static int apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task, uint32_t xfrfilenr) { char zone_buf[3072]; char log_buf[5120]; 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; uint32_t i; int num_bytes = 0; assert(zonedb); /* read zone name and serial */ if(!diff_read_32(in, &type)) { log_msg(LOG_ERR, "diff file too short"); return 0; } if(type != DIFF_PART_XFRF) { log_msg(LOG_ERR, "xfr file has wrong format"); return 0; } /* committed and num_parts are first because they need to be * updated once the rest is written. The log buf is not certain * until its done, so at end of file. The patname is in case a * new zone is created, we know what the options-pattern is */ if(!diff_read_8(in, &committed) || !diff_read_32(in, &num_parts) || !diff_read_64(in, &time_end_0) || !diff_read_32(in, &time_end_1) || !diff_read_32(in, &old_serial) || !diff_read_32(in, &new_serial) || !diff_read_64(in, &time_start_0) || !diff_read_32(in, &time_start_1) || !diff_read_str(in, zone_buf, sizeof(zone_buf)) || !diff_read_str(in, patname_buf, sizeof(patname_buf))) { log_msg(LOG_ERR, "diff file bad commit part"); return 0; } /* has been read in completely */ if(strcmp(zone_buf, domain_to_string(zonedb->apex)) != 0) { log_msg(LOG_ERR, "file %s does not match task %s", zone_buf, domain_to_string(zonedb->apex)); return 0; } if(!committed) { log_msg(LOG_ERR, "diff file %s was not committed", zone_buf); return 0; } if(num_parts == 0) { log_msg(LOG_ERR, "diff file %s was not completed", zone_buf); return 0; } if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "skipping diff file commit with bad serial")); return 1; } if(committed) { int is_axfr=0, delete_mode=0, rr_count=0, softfail=0; const dname_type* apex = domain_dname_const(zonedb->apex); udb_ptr z; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf)); memset(&z, 0, sizeof(z)); /* if udb==NULL, have &z defined */ if(nsd->db->udb) { if(udb_base_get_userflags(nsd->db->udb) != 0) { log_msg(LOG_ERR, "database corrupted, cannot update"); xfrd_unlink_xfrfile(nsd, xfrfilenr); exit(1); } /* all parts were checked by xfrd before commit */ if(!udb_zone_search(nsd->db->udb, &z, dname_name(apex), apex->name_size)) { /* create it */ if(!udb_zone_create(nsd->db->udb, &z, dname_name(apex), apex->name_size)) { /* out of disk space perhaps */ log_msg(LOG_ERR, "could not udb_create_zone " "%s, disk space full?", log_buf); return 0; } } /* set the udb dirty until we are finished applying changes */ udb_base_set_userflags(nsd->db->udb, 1); } /* read and apply all of the parts */ for(i=0; idb, in, zone_buf, new_serial, opt, i, num_parts, &is_axfr, &delete_mode, &rr_count, (nsd->db->udb?&z:NULL), &zonedb, patname_buf, &num_bytes, &softfail); assert(zonedb); if(ret == 0) { log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf); xfrd_unlink_xfrfile(nsd, xfrfilenr); /* the udb is still dirty, it is bad */ exit(1); } else if(ret == 2) { break; } } if(nsd->db->udb) udb_base_set_userflags(nsd->db->udb, 0); /* read the final log_str: but do not fail on it */ if(!diff_read_str(in, log_buf, sizeof(log_buf))) { log_msg(LOG_ERR, "could not read log for transfer %s", zone_buf); snprintf(log_buf, sizeof(log_buf), "error reading log"); } #ifdef NSEC3 if(zonedb) prehash_zone(nsd->db, zonedb); #endif /* NSEC3 */ zonedb->is_changed = 1; if(nsd->db->udb) { ZONE(&z)->is_changed = 1; ZONE(&z)->mtime = time_end_0; ZONE(&z)->mtime_nsec = time_end_1*1000; udb_zone_set_log_str(nsd->db->udb, &z, log_buf); udb_zone_set_file_str(nsd->db->udb, &z, NULL); udb_ptr_unlink(&z, nsd->db->udb); } else { zonedb->mtime.tv_sec = time_end_0; zonedb->mtime.tv_nsec = time_end_1*1000; if(zonedb->logstr) region_recycle(nsd->db->region, zonedb->logstr, strlen(zonedb->logstr)+1); zonedb->logstr = region_strdup(nsd->db->region, log_buf); if(zonedb->filename) region_recycle(nsd->db->region, zonedb->filename, strlen(zonedb->filename)+1); zonedb->filename = NULL; } if(softfail && taskudb && !is_axfr) { log_msg(LOG_ERR, "Failed to apply IXFR cleanly " "(deletes nonexistent RRs, adds existing RRs). " "Zone %s contents is different from master, " "starting AXFR. Transfer %s", zone_buf, log_buf); /* add/del failures in IXFR, get an AXFR */ task_new_soainfo(taskudb, last_task, zonedb, 1); } else { if(taskudb) task_new_soainfo(taskudb, last_task, zonedb, 0); } if(1 <= verbosity) { double elapsed = (double)(time_end_0 - time_start_0)+ (double)((double)time_end_1 -(double)time_start_1) / 1000000.0; VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds", zone_buf, log_buf, num_bytes, elapsed)); } } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf)); } return 1; } struct udb_base* task_file_create(const char* file) { return udb_base_create_new(file, &namedb_walkfunc, NULL); } static int task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e, size_t sz, const dname_type* zname) { if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) { return 0; } if(udb_ptr_is_null(last)) { udb_base_set_userdata(udb, e->data); } else { udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e); } udb_ptr_set_ptr(last, udb, e); /* fill in tasklist item */ udb_rel_ptr_init(&TASKLIST(e)->next); TASKLIST(e)->size = sz; TASKLIST(e)->oldserial = 0; TASKLIST(e)->newserial = 0; TASKLIST(e)->yesno = 0; if(zname) { memmove(TASKLIST(e)->zname, zname, dname_total_size(zname)); } return 1; } void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z, int gone) { /* calculate size */ udb_ptr e; size_t sz; const dname_type* apex, *ns, *em; if(!z || !z->apex || !domain_dname(z->apex)) return; /* safety check */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s", domain_to_string(z->apex))); apex = domain_dname(z->apex); sz = sizeof(struct task_list_d) + dname_total_size(apex); if(z->soa_rrset && !gone) { ns = domain_dname(rdata_atom_domain( z->soa_rrset->rrs[0].rdatas[0])); em = domain_dname(rdata_atom_domain( z->soa_rrset->rrs[0].rdatas[1])); sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2 + ns->name_size + em->name_size; } else { ns = 0; em = 0; } /* create new task_list item */ if(!task_create_new_elem(udb, last, &e, sz, apex)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO"); return; } TASKLIST(&e)->task_type = task_soa_info; if(z->soa_rrset && !gone) { uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl); uint8_t* p = (uint8_t*)TASKLIST(&e)->zname; p += dname_total_size(apex); memmove(p, &ttl, sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, &ns->name_size, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(p, dname_name(ns), ns->name_size); p += ns->name_size; memmove(p, &em->name_size, sizeof(uint8_t)); p += sizeof(uint8_t); memmove(p, dname_name(em), em->name_size); p += em->name_size; memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]), sizeof(uint32_t)); p += sizeof(uint32_t); memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]), sizeof(uint32_t)); } udb_ptr_unlink(&e, udb); } void task_process_sync(struct udb_base* taskudb) { /* need to sync before other process uses the mmap? */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d", taskudb->fname, (int)taskudb->base_size)); (void)taskudb; } void task_remap(struct udb_base* taskudb) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d", taskudb->fname, (int)taskudb->glob_data->fsize)); udb_base_remap_process(taskudb); } void task_clear(struct udb_base* taskudb) { udb_ptr t, n; udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb)); udb_base_set_userdata(taskudb, 0); udb_ptr_init(&n, taskudb); while(!udb_ptr_is_null(&t)) { udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next); udb_rptr_zero(&TASKLIST(&t)->next, taskudb); udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size); udb_ptr_set_ptr(&t, taskudb, &n); } udb_ptr_unlink(&t, taskudb); udb_ptr_unlink(&n, taskudb); } void task_new_expire(struct udb_base* udb, udb_ptr* last, const struct dname* z, int expired) { udb_ptr e; if(!z) return; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s", dname_to_string(z,NULL))); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ dname_total_size(z), z)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add expire"); return; } TASKLIST(&e)->task_type = task_expire; TASKLIST(&e)->yesno = expired; udb_ptr_unlink(&e, udb); } void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + (zone?dname_total_size(zone):0), zone)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones"); return; } TASKLIST(&e)->task_type = task_check_zonefiles; TASKLIST(&e)->yesno = (zone!=NULL); udb_ptr_unlink(&e, udb); } void task_new_write_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + (zone?dname_total_size(zone):0), zone)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones"); return; } TASKLIST(&e)->task_type = task_write_zonefiles; TASKLIST(&e)->yesno = (zone!=NULL); udb_ptr_unlink(&e, udb); } void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v"); return; } TASKLIST(&e)->task_type = task_set_verbosity; TASKLIST(&e)->yesno = v; udb_ptr_unlink(&e, udb); } #ifdef BIND8_STATS void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat, size_t child_count) { void* p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task stat_info")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ sizeof(*stat) + sizeof(stc_type)*child_count, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add stati"); return NULL; } TASKLIST(&e)->task_type = task_stat_info; p = TASKLIST(&e)->zname; memcpy(p, stat, sizeof(*stat)); udb_ptr_unlink(&e, udb); return p + sizeof(*stat); } #endif /* BIND8_STATS */ void task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone, const char* pattern, unsigned zonestatid) { size_t zlen = strlen(zone); size_t plen = strlen(pattern); void *p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern)); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ zlen + 1 + plen + 1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addz"); return; } TASKLIST(&e)->task_type = task_add_zone; TASKLIST(&e)->yesno = zonestatid; p = TASKLIST(&e)->zname; memcpy(p, zone, zlen+1); memmove(p+zlen+1, pattern, plen+1); udb_ptr_unlink(&e, udb); } void task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0))); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +dname_total_size(dname), dname)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delz"); return; } TASKLIST(&e)->task_type = task_del_zone; udb_ptr_unlink(&e, udb); } void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key) { char* p; udb_ptr e; assert(key->name && key->algorithm && key->secret); DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(key->name)+1+strlen(key->algorithm)+1+ strlen(key->secret)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addk"); return; } TASKLIST(&e)->task_type = task_add_key; p = (char*)TASKLIST(&e)->zname; memmove(p, key->name, strlen(key->name)+1); p+=strlen(key->name)+1; memmove(p, key->algorithm, strlen(key->algorithm)+1); p+=strlen(key->algorithm)+1; memmove(p, key->secret, strlen(key->secret)+1); udb_ptr_unlink(&e, udb); } void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name) { char* p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(name)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delk"); return; } TASKLIST(&e)->task_type = task_del_key; p = (char*)TASKLIST(&e)->zname; memmove(p, name, strlen(name)+1); udb_ptr_unlink(&e, udb); } void task_new_add_pattern(udb_base* udb, udb_ptr* last, struct pattern_options* p) { region_type* temp; buffer_type* buffer; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname)); temp = region_create(xalloc, free); buffer = buffer_create(temp, 4096); pattern_options_marshal(buffer, p); buffer_flip(buffer); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + buffer_limit(buffer), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add addp"); region_destroy(temp); return; } TASKLIST(&e)->task_type = task_add_pattern; TASKLIST(&e)->yesno = buffer_limit(buffer); memmove(TASKLIST(&e)->zname, buffer_begin(buffer), buffer_limit(buffer)); udb_ptr_unlink(&e, udb); region_destroy(temp); } void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name) { char* p; udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name)); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +strlen(name)+1, NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add delp"); return; } TASKLIST(&e)->task_type = task_del_pattern; p = (char*)TASKLIST(&e)->zname; memmove(p, name, strlen(name)+1); udb_ptr_unlink(&e, udb); } void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c"); return; } TASKLIST(&e)->task_type = task_opt_change; #ifdef RATELIMIT TASKLIST(&e)->oldserial = opt->rrl_ratelimit; TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit; TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip; #else (void)opt; #endif udb_ptr_unlink(&e, udb); } void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task zonestat_inc")); if(sz == 0) return; /* no need to decrease to 0 */ if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add z_i"); return; } TASKLIST(&e)->task_type = task_zonestat_inc; TASKLIST(&e)->oldserial = (uint32_t)sz; udb_ptr_unlink(&e, udb); } int task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname, uint32_t old_serial, uint32_t new_serial, uint64_t filenumber) { udb_ptr e; DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +dname_total_size(dname), dname)) { log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr"); return 0; } TASKLIST(&e)->oldserial = old_serial; TASKLIST(&e)->newserial = new_serial; TASKLIST(&e)->yesno = filenumber; TASKLIST(&e)->task_type = task_apply_xfr; udb_ptr_unlink(&e, udb); return 1; } void task_process_expire(namedb_type* db, struct task_list_d* task) { uint8_t ok; zone_type* z = namedb_find_zone(db, task->zname); assert(task->task_type == task_expire); if(!z) { DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree", dname_to_string(task->zname, NULL), task->yesno?"expired":"unexpired")); return; } DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s", dname_to_string(task->zname,0), task->yesno?"expired":"unexpired")); /* find zone, set expire flag */ ok = !task->yesno; /* only update zone->is_ok if needed to minimize copy-on-write * of memory pages shared after fork() */ if(ok && !z->is_ok) z->is_ok = 1; else if(!ok && z->is_ok) z->is_ok = 0; } static void task_process_set_verbosity(struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno)); verbosity = task->yesno; } static void task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, struct task_list_d* task) { /* on SIGHUP check if zone-text-files changed and if so, * reread. When from xfrd-reload, no need to fstat the files */ if(task->yesno) { struct zone_options* zo = zone_options_find(nsd->options, task->zname); if(zo) namedb_check_zonefile(nsd, udb, last_task, zo); } else { /* check all zones */ namedb_check_zonefiles(nsd, nsd->options, udb, last_task); } } static void task_process_writezones(struct nsd* nsd, struct task_list_d* task) { if(task->yesno) { struct zone_options* zo = zone_options_find(nsd->options, task->zname); if(zo) namedb_write_zonefile(nsd, zo); } else { namedb_write_zonefiles(nsd, nsd->options); } } static void task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, struct task_list_d* task) { zone_type* z; const dname_type* zdname; const char* zname = (const char*)task->zname; const char* pname = zname + strlen(zname)+1; DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname)); zdname = dname_parse(nsd->db->region, zname); if(!zdname) { log_msg(LOG_ERR, "can not parse zone name %s", zname); return; } /* create zone */ z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname); if(!z) { region_recycle(nsd->db->region, (void*)zdname, dname_total_size(zdname)); log_msg(LOG_ERR, "can not add zone %s %s", zname, pname); return; } z->zonestatid = (unsigned)task->yesno; /* if zone is empty, attempt to read the zonefile from disk (if any) */ if(!z->soa_rrset && z->opts->pattern->zonefile) { namedb_read_zonefile(nsd, z, udb, last_task); } } static void task_process_del_zone(struct nsd* nsd, struct task_list_d* task) { zone_type* zone; struct zone_options* zopt; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string( task->zname, NULL))); zone = namedb_find_zone(nsd->db, task->zname); if(!zone) return; #ifdef NSEC3 nsec3_clear_precompile(nsd->db, zone); zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); if(nsd->db->udb) { udb_ptr udbz; if(udb_zone_search(nsd->db->udb, &udbz, dname_name(task->zname), task->zname->name_size)) { udb_zone_delete(nsd->db->udb, &udbz); udb_ptr_unlink(&udbz, nsd->db->udb); } } /* remove from zonetree, apex, soa */ zopt = zone->opts; namedb_zone_delete(nsd->db, zone); /* remove from options (zone_list already edited by xfrd) */ zone_options_delete(nsd->options, zopt); } static void task_process_add_key(struct nsd* nsd, struct task_list_d* task) { struct key_options key; key.name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name)); key.algorithm = key.name + strlen(key.name)+1; key.secret = key.algorithm + strlen(key.algorithm)+1; key_options_add_modify(nsd->options, &key); memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */ } static void task_process_del_key(struct nsd* nsd, struct task_list_d* task) { char* name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name)); /* this is reload and nothing is using the TSIG key right now */ key_options_remove(nsd->options, name); } static void task_process_add_pattern(struct nsd* nsd, struct task_list_d* task) { region_type* temp = region_create(xalloc, free); buffer_type buffer; struct pattern_options *pat; buffer_create_from(&buffer, task->zname, task->yesno); pat = pattern_options_unmarshal(temp, &buffer); DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname)); pattern_options_add_modify(nsd->options, pat); region_destroy(temp); } static void task_process_del_pattern(struct nsd* nsd, struct task_list_d* task) { char* name = (char*)task->zname; DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name)); pattern_options_remove(nsd->options, name); } static void task_process_opt_change(struct nsd* nsd, struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task")); #ifdef RATELIMIT nsd->options->rrl_ratelimit = task->oldserial; nsd->options->rrl_whitelist_ratelimit = task->newserial; nsd->options->rrl_slip = task->yesno; rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit, nsd->options->rrl_slip); #else (void)nsd; (void)task; #endif } #ifdef USE_ZONE_STATS static void task_process_zonestat_inc(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, struct task_list_d* task) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "zonestat_inc task %u", (unsigned)task->oldserial)); nsd->zonestatdesired = (unsigned)task->oldserial; /* send echo to xfrd to increment on its end */ task_new_zonestat_inc(udb, last_task, nsd->zonestatdesired); } #endif static void task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task) { /* we have to use an udb_ptr task here, because the apply_xfr procedure * appends soa_info which may remap and change the pointer. */ zone_type* zone; FILE* df; DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string( TASKLIST(task)->zname, NULL))); zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname); if(!zone) { /* assume the zone has been deleted and a zone transfer was * still waiting to be processed */ xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno); return; } /* apply the XFR */ /* oldserial, newserial, yesno is filenumber */ df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r"); if(!df) { /* could not open file to update */ /* there is no reply to xfrd failed-update, * because xfrd has a scan for apply-failures. */ xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno); return; } /* read and apply zone transfer */ if(!apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, last_task, TASKLIST(task)->yesno)) { /* there is no reply to xfrd failed-update, * because xfrd has a scan for apply-failures. */ } fclose(df); xfrd_unlink_xfrfile(nsd, TASKLIST(task)->yesno); } void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, udb_ptr* task) { switch(TASKLIST(task)->task_type) { case task_expire: task_process_expire(nsd->db, TASKLIST(task)); break; case task_check_zonefiles: task_process_checkzones(nsd, udb, last_task, TASKLIST(task)); break; case task_write_zonefiles: task_process_writezones(nsd, TASKLIST(task)); break; case task_set_verbosity: task_process_set_verbosity(TASKLIST(task)); break; case task_add_zone: task_process_add_zone(nsd, udb, last_task, TASKLIST(task)); break; case task_del_zone: task_process_del_zone(nsd, TASKLIST(task)); break; case task_add_key: task_process_add_key(nsd, TASKLIST(task)); break; case task_del_key: task_process_del_key(nsd, TASKLIST(task)); break; case task_add_pattern: task_process_add_pattern(nsd, TASKLIST(task)); break; case task_del_pattern: task_process_del_pattern(nsd, TASKLIST(task)); break; case task_opt_change: task_process_opt_change(nsd, TASKLIST(task)); break; #ifdef USE_ZONE_STATS case task_zonestat_inc: task_process_zonestat_inc(nsd, udb, last_task, TASKLIST(task)); break; #endif case task_apply_xfr: task_process_apply_xfr(nsd, udb, last_task, task); break; default: log_msg(LOG_WARNING, "unhandled task in reload type %d", (int)TASKLIST(task)->task_type); break; } udb_ptr_free_space(task, udb, TASKLIST(task)->size); } nsd-4.1.26/radtree.c0000664000175000017500000011261113040156013013613 0ustar wouterwouter/* * radtree -- generic radix tree for binary strings. * * Copyright (c) 2010, NLnet Labs. See LICENSE for license. */ #include "config.h" #include #include #include #include #include #include "radtree.h" #include "util.h" #include "region-allocator.h" #include #include struct radtree* radix_tree_create(struct region* region) { struct radtree* rt = (struct radtree*)region_alloc(region, sizeof(*rt)); if(!rt) return NULL; rt->region = region; radix_tree_init(rt); return rt; } void radix_tree_init(struct radtree* rt) { rt->root = NULL; rt->count = 0; } /** delete radnodes in postorder recursion */ static void radnode_del_postorder(struct region* region, struct radnode* n) { unsigned i; if(!n) return; for(i=0; ilen; i++) { radnode_del_postorder(region, n->array[i].node); region_recycle(region, n->array[i].str, n->array[i].len); } region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(region, n, sizeof(*n)); } void radix_tree_clear(struct radtree* rt) { radnode_del_postorder(rt->region, rt->root); rt->root = NULL; rt->count = 0; } void radix_tree_delete(struct radtree* rt) { if(!rt) return; radix_tree_clear(rt); region_recycle(rt->region, rt, sizeof(*rt)); } /** return last elem-containing node in this subtree (excl self) */ static struct radnode* radnode_last_in_subtree(struct radnode* n) { int idx; /* try last entry in array first */ for(idx=((int)n->len)-1; idx >= 0; idx--) { if(n->array[idx].node) { /* does it have entries in its subtrees? */ if(n->array[idx].node->len > 0) { struct radnode* s = radnode_last_in_subtree( n->array[idx].node); if(s) return s; } /* no, does it have an entry itself? */ if(n->array[idx].node->elem) return n->array[idx].node; } } return NULL; } /** last in subtree, incl self */ static struct radnode* radnode_last_in_subtree_incl_self(struct radnode* n) { struct radnode* s = radnode_last_in_subtree(n); if(s) return s; if(n->elem) return n; return NULL; } /** return first elem-containing node in this subtree (excl self) */ static struct radnode* radnode_first_in_subtree(struct radnode* n) { unsigned idx; struct radnode* s; /* try every subnode */ for(idx=0; idxlen; idx++) { if(n->array[idx].node) { /* does it have elem itself? */ if(n->array[idx].node->elem) return n->array[idx].node; /* try its subtrees */ if((s=radnode_first_in_subtree(n->array[idx].node))!=0) return s; } } return NULL; } /** Find an entry in arrays from idx-1 to 0 */ static struct radnode* radnode_find_prev_from_idx(struct radnode* n, unsigned from) { unsigned idx = from; while(idx > 0) { idx --; if(n->array[idx].node) { struct radnode* s = radnode_last_in_subtree_incl_self( n->array[idx].node); if(s) return s; } } return NULL; } /** * Find a prefix of the key, in whole-nodes. * Finds the longest prefix that corresponds to a whole radnode entry. * There may be a slightly longer prefix in one of the array elements. * @param result: the longest prefix, the entry itself if *respos==len, * otherwise an array entry, residx. * @param respos: pos in string where next unmatched byte is, if == len an * exact match has been found. If == 0 then a "" match was found. * @return false if no prefix found, not even the root "" prefix. */ static int radix_find_prefix_node(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result, radstrlen_type* respos) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; *respos = 0; *result = n; if(!n) return 0; while(n) { if(pos == len) { return 1; } byte = k[pos]; if(byte < n->offset) { return 1; } byte -= n->offset; if(byte >= n->len) { return 1; } pos++; if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) { return 1; } if(memcmp(&k[pos], n->array[byte].str, n->array[byte].len) != 0) { return 1; } pos += n->array[byte].len; } n = n->array[byte].node; if(!n) return 1; *respos = pos; *result = n; } return 1; } /** grow array to at least the given size, offset unchanged */ static int radnode_array_grow(struct region* region, struct radnode* n, unsigned want) { unsigned ns = ((unsigned)n->capacity)*2; struct radsel* a; assert(want <= 256); /* cannot be more, range of uint8 */ if(want > ns) ns = want; if(ns > 256) ns = 256; /* we do not use realloc, because we want to keep the old array * in case alloc fails, so that the tree is still usable */ a = (struct radsel*)region_alloc_array(region, ns, sizeof(struct radsel)); if(!a) return 0; assert(n->len <= n->capacity); assert(n->capacity < ns); memcpy(&a[0], &n->array[0], n->len*sizeof(struct radsel)); region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); n->array = a; n->capacity = ns; return 1; } /** make space in radnode array for another byte */ static int radnode_array_space(struct region* region, struct radnode* n, uint8_t byte) { /* is there an array? */ if(!n->array || n->capacity == 0) { n->array = (struct radsel*)region_alloc(region, sizeof(struct radsel)); if(!n->array) return 0; memset(&n->array[0], 0, sizeof(struct radsel)); n->len = 1; n->capacity = 1; n->offset = byte; /* is the array unused? */ } else if(n->len == 0 && n->capacity != 0) { n->len = 1; n->offset = byte; memset(&n->array[0], 0, sizeof(struct radsel)); /* is it below the offset? */ } else if(byte < n->offset) { /* is capacity enough? */ unsigned idx; unsigned need = n->offset-byte; if(n->len+need > n->capacity) { /* grow array */ if(!radnode_array_grow(region, n, n->len+need)) return 0; } /* reshuffle items to end */ memmove(&n->array[need], &n->array[0], n->len*sizeof(struct radsel)); /* fixup pidx */ for(idx = 0; idx < n->len; idx++) { if(n->array[idx+need].node) n->array[idx+need].node->pidx = idx+need; } /* zero the first */ memset(&n->array[0], 0, need*sizeof(struct radsel)); n->len += need; n->offset = byte; /* is it above the max? */ } else if(byte-n->offset >= n->len) { /* is capacity enough? */ unsigned need = (byte-n->offset) - n->len + 1; /* grow array */ if(n->len + need > n->capacity) { if(!radnode_array_grow(region, n, n->len+need)) return 0; } /* zero added entries */ memset(&n->array[n->len], 0, need*sizeof(struct radsel)); /* grow length */ n->len += need; } return 1; } /** create a prefix in the array strs */ static int radsel_str_create(struct region* region, struct radsel* r, uint8_t* k, radstrlen_type pos, radstrlen_type len) { r->str = (uint8_t*)region_alloc(region, sizeof(uint8_t)*(len-pos)); if(!r->str) return 0; /* out of memory */ memmove(r->str, k+pos, len-pos); r->len = len-pos; return 1; } /** see if one byte string p is a prefix of another x (equality is true) */ static int bstr_is_prefix(uint8_t* p, radstrlen_type plen, uint8_t* x, radstrlen_type xlen) { /* if plen is zero, it is an (empty) prefix */ if(plen == 0) return 1; /* if so, p must be shorter */ if(plen > xlen) return 0; return (memcmp(p, x, plen) == 0); } /** number of bytes in common for the two strings */ static radstrlen_type bstr_common(uint8_t* x, radstrlen_type xlen, uint8_t* y, radstrlen_type ylen) { unsigned i, max = ((xlenstr, r->len)) { uint8_t* split_str=NULL, *dupstr=NULL; radstrlen_type split_len=0; /* 'add' is a prefix of r.node */ /* also for empty addstr */ /* set it up so that the 'add' node has r.node as child */ /* so, r.node gets moved below the 'add' node, but we do * this so that the r.node stays the same pointer for its * key name */ assert(addlen != r->len); assert(addlen < r->len); if(r->len-addlen > 1) { /* shift one because a char is in the lookup array */ if(!radsel_prefix_remainder(region, addlen+1, r->str, r->len, &split_str, &split_len)) return 0; } if(addlen != 0) { dupstr = (uint8_t*)region_alloc(region, addlen*sizeof(uint8_t)); if(!dupstr) { region_recycle(region, split_str, split_len); return 0; } memcpy(dupstr, addstr, addlen); } if(!radnode_array_space(region, add, r->str[addlen])) { region_recycle(region, split_str, split_len); region_recycle(region, dupstr, addlen); return 0; } /* alloc succeeded, now link it in */ add->parent = r->node->parent; add->pidx = r->node->pidx; add->array[0].node = r->node; add->array[0].str = split_str; add->array[0].len = split_len; r->node->parent = add; r->node->pidx = 0; r->node = add; region_recycle(region, r->str, r->len); r->str = dupstr; r->len = addlen; } else if(bstr_is_prefix(r->str, r->len, addstr, addlen)) { uint8_t* split_str = NULL; radstrlen_type split_len = 0; /* r.node is a prefix of 'add' */ /* set it up so that the 'r.node' has 'add' as child */ /* and basically, r.node is already completely fine, * we only need to create a node as its child */ assert(addlen != r->len); assert(r->len < addlen); if(addlen-r->len > 1) { /* shift one because a character goes into array */ if(!radsel_prefix_remainder(region, r->len+1, addstr, addlen, &split_str, &split_len)) return 0; } if(!radnode_array_space(region, r->node, addstr[r->len])) { region_recycle(region, split_str, split_len); return 0; } /* alloc succeeded, now link it in */ add->parent = r->node; add->pidx = addstr[r->len] - r->node->offset; r->node->array[add->pidx].node = add; r->node->array[add->pidx].str = split_str; r->node->array[add->pidx].len = split_len; } else { /* okay we need to create a new node that chooses between * the nodes 'add' and r.node * We do this so that r.node stays the same pointer for its * key name. */ struct radnode* com; uint8_t* common_str=NULL, *s1_str=NULL, *s2_str=NULL; radstrlen_type common_len, s1_len=0, s2_len=0; common_len = bstr_common(r->str, r->len, addstr, addlen); assert(common_len < r->len); assert(common_len < addlen); /* create the new node for choice */ com = (struct radnode*)region_alloc_zero(region, sizeof(*com)); if(!com) return 0; /* out of memory */ /* create the two substrings for subchoices */ if(r->len-common_len > 1) { /* shift by one char because it goes in lookup array */ if(!radsel_prefix_remainder(region, common_len+1, r->str, r->len, &s1_str, &s1_len)) { region_recycle(region, com, sizeof(*com)); return 0; } } if(addlen-common_len > 1) { if(!radsel_prefix_remainder(region, common_len+1, addstr, addlen, &s2_str, &s2_len)) { region_recycle(region, com, sizeof(*com)); region_recycle(region, s1_str, s1_len); return 0; } } /* create the shared prefix to go in r */ if(common_len > 0) { common_str = (uint8_t*)region_alloc(region, common_len*sizeof(uint8_t)); if(!common_str) { region_recycle(region, com, sizeof(*com)); region_recycle(region, s1_str, s1_len); region_recycle(region, s2_str, s2_len); return 0; } memcpy(common_str, addstr, common_len); } /* make space in the common node array */ if(!radnode_array_space(region, com, r->str[common_len]) || !radnode_array_space(region, com, addstr[common_len])) { region_recycle(region, com->array, com->capacity*sizeof(struct radsel)); region_recycle(region, com, sizeof(*com)); region_recycle(region, common_str, common_len); region_recycle(region, s1_str, s1_len); region_recycle(region, s2_str, s2_len); return 0; } /* allocs succeeded, proceed to link it all up */ com->parent = r->node->parent; com->pidx = r->node->pidx; r->node->parent = com; r->node->pidx = r->str[common_len]-com->offset; add->parent = com; add->pidx = addstr[common_len]-com->offset; com->array[r->node->pidx].node = r->node; com->array[r->node->pidx].str = s1_str; com->array[r->node->pidx].len = s1_len; com->array[add->pidx].node = add; com->array[add->pidx].str = s2_str; com->array[add->pidx].len = s2_len; region_recycle(region, r->str, r->len); r->str = common_str; r->len = common_len; r->node = com; } return 1; } struct radnode* radix_insert(struct radtree* rt, uint8_t* k, radstrlen_type len, void* elem) { struct radnode* n; radstrlen_type pos = 0; /* create new element to add */ struct radnode* add = (struct radnode*)region_alloc_zero(rt->region, sizeof(*add)); if(!add) return NULL; /* out of memory */ add->elem = elem; /* find out where to add it */ if(!radix_find_prefix_node(rt, k, len, &n, &pos)) { /* new root */ assert(rt->root == NULL); if(len == 0) { rt->root = add; } else { /* add a root to point to new node */ n = (struct radnode*)region_alloc_zero(rt->region, sizeof(*n)); if(!n) return NULL; if(!radnode_array_space(rt->region, n, k[0])) { region_recycle(rt->region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(rt->region, n, sizeof(*n)); region_recycle(rt->region, add, sizeof(*add)); return NULL; } add->parent = n; add->pidx = 0; n->array[0].node = add; if(len > 1) { if(!radsel_prefix_remainder(rt->region, 1, k, len, &n->array[0].str, &n->array[0].len)) { region_recycle(rt->region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(rt->region, n, sizeof(*n)); region_recycle(rt->region, add, sizeof(*add)); return NULL; } } rt->root = n; } } else if(pos == len) { /* found an exact match */ if(n->elem) { /* already exists, failure */ region_recycle(rt->region, add, sizeof(*add)); return NULL; } n->elem = elem; region_recycle(rt->region, add, sizeof(*add)); add = n; } else { /* n is a node which can accomodate */ uint8_t byte; assert(pos < len); byte = k[pos]; /* see if it falls outside of array */ if(byte < n->offset || byte-n->offset >= n->len) { /* make space in the array for it; adjusts offset */ if(!radnode_array_space(rt->region, n, byte)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } assert(byte>=n->offset && byte-n->offsetlen); byte -= n->offset; /* see if more prefix needs to be split off */ if(pos+1 < len) { if(!radsel_str_create(rt->region, &n->array[byte], k, pos+1, len)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } /* insert the new node in the new bucket */ add->parent = n; add->pidx = byte; n->array[byte].node = add; /* so a bucket exists and byte falls in it */ } else if(n->array[byte-n->offset].node == NULL) { /* use existing bucket */ byte -= n->offset; if(pos+1 < len) { /* split off more prefix */ if(!radsel_str_create(rt->region, &n->array[byte], k, pos+1, len)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } /* insert the new node in the new bucket */ add->parent = n; add->pidx = byte; n->array[byte].node = add; } else { /* use bucket but it has a shared prefix, * split that out and create a new intermediate * node to split out between the two. * One of the two might exactmatch the new * intermediate node */ if(!radsel_split(rt->region, &n->array[byte-n->offset], k, pos+1, len, add)) { region_recycle(rt->region, add, sizeof(*add)); return NULL; } } } rt->count ++; return add; } /** Delete a radnode */ static void radnode_delete(struct region* region, struct radnode* n) { unsigned i; if(!n) return; for(i=0; ilen; i++) { /* safe to free NULL str */ region_recycle(region, n->array[i].str, n->array[i].len); } region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); region_recycle(region, n, sizeof(*n)); } /** Cleanup node with one child, it is removed and joined into parent[x] str */ static int radnode_cleanup_onechild(struct region* region, struct radnode* n, struct radnode* par) { uint8_t* join; radstrlen_type joinlen; uint8_t pidx = n->pidx; struct radnode* child = n->array[0].node; /* node had one child, merge them into the parent. */ /* keep the child node, so its pointers stay valid. */ /* at parent, append child->str to array str */ assert(pidx < par->len); joinlen = par->array[pidx].len + n->array[0].len + 1; join = (uint8_t*)region_alloc(region, joinlen*sizeof(uint8_t)); if(!join) { /* cleanup failed due to out of memory */ /* the tree is inefficient, with node n still existing */ return 0; } /* we know that .str and join are malloced, thus aligned */ if(par->array[pidx].str) memcpy(join, par->array[pidx].str, par->array[pidx].len); /* the array lookup is gone, put its character in the lookup string*/ join[par->array[pidx].len] = child->pidx + n->offset; /* but join+len may not be aligned */ if(n->array[0].str) memmove(join+par->array[pidx].len+1, n->array[0].str, n->array[0].len); region_recycle(region, par->array[pidx].str, par->array[pidx].len); par->array[pidx].str = join; par->array[pidx].len = joinlen; /* and set the node to our child. */ par->array[pidx].node = child; child->parent = par; child->pidx = pidx; /* we are unlinked, delete our node */ radnode_delete(region, n); return 1; } /** remove array of nodes */ static void radnode_array_clean_all(struct region* region, struct radnode* n) { n->offset = 0; n->len = 0; /* shrink capacity */ region_recycle(region, n->array, n->capacity*sizeof(struct radsel)); n->array = NULL; n->capacity = 0; } /** see if capacity can be reduced for the given node array */ static void radnode_array_reduce_if_needed(struct region* region, struct radnode* n) { if(n->len <= n->capacity/2 && n->len != n->capacity) { struct radsel* a = (struct radsel*)region_alloc_array(region, sizeof(*a), n->len); if(!a) return; memcpy(a, n->array, sizeof(*a)*n->len); region_recycle(region, n->array, n->capacity*sizeof(*a)); n->array = a; n->capacity = n->len; } } /** remove NULL nodes from front of array */ static void radnode_array_clean_front(struct region* region, struct radnode* n) { /* move them up and adjust offset */ unsigned idx, shuf = 0; /* remove until a nonNULL entry */ while(shuf < n->len && n->array[shuf].node == NULL) shuf++; if(shuf == 0) return; if(shuf == n->len) { /* the array is empty, the tree is inefficient */ radnode_array_clean_all(region, n); return; } assert(shuf < n->len); assert((int)shuf <= 255-(int)n->offset); memmove(&n->array[0], &n->array[shuf], (n->len - shuf)*sizeof(struct radsel)); n->offset += shuf; n->len -= shuf; for(idx=0; idxlen; idx++) if(n->array[idx].node) n->array[idx].node->pidx = idx; /* see if capacity can be reduced */ radnode_array_reduce_if_needed(region, n); } /** remove NULL nodes from end of array */ static void radnode_array_clean_end(struct region* region, struct radnode* n) { /* shorten it */ unsigned shuf = 0; /* remove until a nonNULL entry */ while(shuf < n->len && n->array[n->len-1-shuf].node == NULL) shuf++; if(shuf == 0) return; if(shuf == n->len) { /* the array is empty, the tree is inefficient */ radnode_array_clean_all(region, n); return; } assert(shuf < n->len); n->len -= shuf; /* array elements can stay where they are */ /* see if capacity can be reduced */ radnode_array_reduce_if_needed(region, n); } /** clean up radnode leaf, where we know it has a parent */ static void radnode_cleanup_leaf(struct region* region, struct radnode* n, struct radnode* par) { uint8_t pidx; /* node was a leaf */ /* delete leaf node, but store parent+idx */ pidx = n->pidx; radnode_delete(region, n); /* set parent+idx entry to NULL str and node.*/ assert(pidx < par->len); region_recycle(region, par->array[pidx].str, par->array[pidx].len); par->array[pidx].str = NULL; par->array[pidx].len = 0; par->array[pidx].node = NULL; /* see if par offset or len must be adjusted */ if(par->len == 1) { /* removed final element from array */ radnode_array_clean_all(region, par); } else if(pidx == 0) { /* removed first element from array */ radnode_array_clean_front(region, par); } else if(pidx == par->len-1) { /* removed last element from array */ radnode_array_clean_end(region, par); } } /** * Cleanup a radix node that was made smaller, see if it can * be merged with others. * @param rt: tree to remove root if needed. * @param n: node to cleanup * @return false on alloc failure. */ static int radnode_cleanup(struct radtree* rt, struct radnode* n) { while(n) { if(n->elem) { /* cannot delete node with a data element */ return 1; } else if(n->len == 1 && n->parent) { return radnode_cleanup_onechild(rt->region, n, n->parent); } else if(n->len == 0) { struct radnode* par = n->parent; if(!par) { /* root deleted */ radnode_delete(rt->region, n); rt->root = NULL; return 1; } /* remove and delete the leaf node */ radnode_cleanup_leaf(rt->region, n, par); /* see if parent can now be cleaned up */ n = par; } else { /* node cannot be cleaned up */ return 1; } } /* ENOTREACH */ return 1; } void radix_delete(struct radtree* rt, struct radnode* n) { if(!n) return; n->elem = NULL; rt->count --; if(!radnode_cleanup(rt, n)) { /* out of memory in cleanup. the elem ptr is NULL, but * the radix tree could be inefficient. */ } } struct radnode* radix_search(struct radtree* rt, uint8_t* k, radstrlen_type len) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; while(n) { if(pos == len) return n->elem?n:NULL; byte = k[pos]; if(byte < n->offset) return NULL; byte -= n->offset; if(byte >= n->len) return NULL; pos++; if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) return NULL; /* no match */ if(memcmp(&k[pos], n->array[byte].str, n->array[byte].len) != 0) return NULL; /* no match */ pos += n->array[byte].len; } n = n->array[byte].node; } return NULL; } /** return self or a previous element */ static int ret_self_or_prev(struct radnode* n, struct radnode** result) { if(n->elem) *result = n; else *result = radix_prev(n); return 0; } int radix_find_less_equal(struct radtree* rt, uint8_t* k, radstrlen_type len, struct radnode** result) { struct radnode* n = rt->root; radstrlen_type pos = 0; uint8_t byte; int r; if(!n) { /* empty tree */ *result = NULL; return 0; } while(pos < len) { byte = k[pos]; if(byte < n->offset) { /* so the previous is the element itself */ /* or something before this element */ return ret_self_or_prev(n, result); } byte -= n->offset; if(byte >= n->len) { /* so, the previous is the last of array, or itself */ /* or something before this element */ if((*result=radnode_last_in_subtree_incl_self(n))==0) *result = radix_prev(n); return 0; } pos++; if(!n->array[byte].node) { /* no match */ /* Find an entry in arrays from byte-1 to 0 */ *result = radnode_find_prev_from_idx(n, byte); if(*result) return 0; /* this entry or something before it */ return ret_self_or_prev(n, result); } if(n->array[byte].len != 0) { /* must match additional string */ if(pos+n->array[byte].len > len) { /* the additional string is longer than key*/ if( (memcmp(&k[pos], n->array[byte].str, len-pos)) <= 0) { /* and the key is before this node */ *result = radix_prev(n->array[byte].node); } else { /* the key is after the additional * string, thus everything in that * subtree is smaller. */ *result=radnode_last_in_subtree_incl_self(n->array[byte].node); /* if somehow that is NULL, * then we have an inefficient tree: * byte+1 is larger than us, so find * something in byte-1 and before */ if(!*result) *result = radix_prev(n->array[byte].node); } return 0; /* no match */ } if( (r=memcmp(&k[pos], n->array[byte].str, n->array[byte].len)) < 0) { *result = radix_prev(n->array[byte].node); return 0; /* no match */ } else if(r > 0) { /* the key is larger than the additional * string, thus everything in that subtree * is smaller */ *result=radnode_last_in_subtree_incl_self(n->array[byte].node); /* if we have an inefficient tree */ if(!*result) *result = radix_prev(n->array[byte].node); return 0; /* no match */ } pos += n->array[byte].len; } n = n->array[byte].node; } if(n->elem) { /* exact match */ *result = n; return 1; } /* there is a node which is an exact match, but it has no element */ *result = radix_prev(n); return 0; } struct radnode* radix_first(struct radtree* rt) { struct radnode* n; if(!rt || !rt->root) return NULL; n = rt->root; if(n->elem) return n; return radix_next(n); } struct radnode* radix_last(struct radtree* rt) { if(!rt || !rt->root) return NULL; return radnode_last_in_subtree_incl_self(rt->root); } struct radnode* radix_next(struct radnode* n) { if(!n) return NULL; if(n->len) { /* go down */ struct radnode* s = radnode_first_in_subtree(n); if(s) return s; } /* go up - the parent->elem is not useful, because it is before us */ while(n->parent) { unsigned idx = n->pidx; n = n->parent; idx++; for(; idx < n->len; idx++) { /* go down the next branch */ if(n->array[idx].node) { struct radnode* s; /* node itself */ if(n->array[idx].node->elem) return n->array[idx].node; /* or subtree */ s = radnode_first_in_subtree( n->array[idx].node); if(s) return s; } } } return NULL; } struct radnode* radix_prev(struct radnode* n) { if(!n) return NULL; /* must go up, since all array nodes are after this node */ while(n->parent) { uint8_t idx = n->pidx; struct radnode* s; n = n->parent; assert(n->len > 0); /* since we are a child */ /* see if there are elements in previous branches there */ s = radnode_find_prev_from_idx(n, idx); if(s) return s; /* the current node is before the array */ if(n->elem) return n; } return NULL; } /** convert one character from domain-name to radname */ static uint8_t char_d2r(uint8_t c) { if(c < 'A') return c+1; /* make space for 00 */ else if(c <= 'Z') return c-'A'+'a'; /* lowercase */ else return c; } /** convert one character from radname to domain-name (still lowercased) */ static uint8_t char_r2d(uint8_t c) { assert(c != 0); /* end of label */ if(c <= 'A') return c-1; else return c; } /** copy and convert a range of characters */ static void cpy_d2r(uint8_t* to, const uint8_t* from, int len) { int i; for(i=0; i= dlen); assert(dlen > 0); /* even root label has dlen=1 */ /* root */ if(dlen == 1) { assert(dname[0] == 0); *len = 0; return; } /* walk through domain name and remember label positions */ do { /* compression pointers not allowed */ if((dname[dpos] & 0xc0)) { *len = 0; return; /* format error */ } labstart[lab++] = &dname[dpos]; if(dpos + dname[dpos] + 1 >= dlen) { *len = 0; return; /* format error */ } /* skip the label contents */ dpos += dname[dpos]; dpos ++; } while(dname[dpos] != 0); /* exit condition makes root label not in labelstart stack */ /* because the root was handled before, we know there is some text */ assert(lab > 0); lab-=1; kpos = *labstart[lab]; cpy_d2r(k, labstart[lab]+1, kpos); /* if there are more labels, copy them over */ while(lab) { /* put 'end-of-label' 00 to end previous label */ k[kpos++]=0; /* append the label */ lab--; cpy_d2r(k+kpos, labstart[lab]+1, *labstart[lab]); kpos += *labstart[lab]; } /* done */ assert(kpos == dlen-2); /* no rootlabel, one less label-marker */ *len = kpos; } /* radname code: radix-bstring to domain */ void radname_r2d(uint8_t* k, radstrlen_type len, uint8_t* dname, size_t* dlen) { /* find labels and push on stack */ uint8_t* labstart[130]; uint8_t lablen[130]; unsigned int lab = 0, dpos, kpos = 0; /* sufficient space */ assert(k && dname); assert((size_t)*dlen >= (size_t)len+2); assert(len <= 256); /* root label */ if(len == 0) { assert(*dlen > 0); dname[0]=0; *dlen=1; return; } /* find labels */ while(kpos < len) { lablen[lab]=0; labstart[lab]=&k[kpos]; /* skip to next label */ while(kpos < len && k[kpos] != 0) { lablen[lab]++; kpos++; } lab++; /* skip 00 byte for label-end */ if(kpos < len) { assert(k[kpos] == 0); kpos++; } } /* copy the labels over to the domain name */ dpos = 0; while(lab) { lab--; /* label length */ dname[dpos++] = lablen[lab]; /* label content */ cpy_r2d(dname+dpos, labstart[lab], lablen[lab]); dpos += lablen[lab]; } /* append root label */ dname[dpos++] = 0; /* assert the domain name is wellformed */ assert((int)dpos == (int)len+2); assert(dname[dpos-1] == 0); /* ends with root label */ *dlen = dpos; } /** insert by domain name */ struct radnode* radname_insert(struct radtree* rt, const uint8_t* d, size_t max, void* elem) { /* convert and insert */ uint8_t radname[300]; radstrlen_type len = (radstrlen_type)sizeof(radname); if(max > sizeof(radname)) return NULL; /* too long */ radname_d2r(radname, &len, d, max); return radix_insert(rt, radname, len, elem); } /** delete by domain name */ void radname_delete(struct radtree* rt, const uint8_t* d, size_t max) { /* search and remove */ struct radnode* n = radname_search(rt, d, max); if(n) radix_delete(rt, n); } /* search for exact match of domain name, converted to radname in tree */ struct radnode* radname_search(struct radtree* rt, const uint8_t* d, size_t max) { /* stack of labels in the domain name */ const uint8_t* labstart[130]; unsigned int lab, dpos, lpos; struct radnode* n = rt->root; uint8_t byte; radstrlen_type i; uint8_t b; /* search for root? it is '' */ if(max < 1) return NULL; if(d[0] == 0) { if(!n) return NULL; return n->elem?n:NULL; } /* find labels stack in domain name */ lab = 0; dpos = 0; /* must have one label, since root is specialcased */ do { if((d[dpos] & 0xc0)) return NULL; /* compression ptrs not allowed error */ labstart[lab++] = &d[dpos]; if(dpos + d[dpos] + 1 >= max) return NULL; /* format error: outside of bounds */ /* skip the label contents */ dpos += d[dpos]; dpos ++; } while(d[dpos] != 0); /* exit condition makes that root label is not in the labstarts */ /* now: dpos+1 is length of domain name. lab is number of labels-1 */ /* start processing at the last label */ lab-=1; lpos = 0; while(n) { /* fetch next byte this label */ if(lpos < *labstart[lab]) /* lpos+1 to skip labelstart, lpos++ to move forward */ byte = char_d2r(labstart[lab][++lpos]); else { if(lab == 0) /* last label - we're done */ return n->elem?n:NULL; /* next label, search for byte 00 */ lpos = 0; lab--; byte = 0; } /* find that byte in the array */ if(byte < n->offset) return NULL; byte -= n->offset; if(byte >= n->len) return NULL; if(n->array[byte].len != 0) { /* must match additional string */ /* see how many bytes we need and start matching them*/ for(i=0; iarray[byte].len; i++) { /* next byte to match */ if(lpos < *labstart[lab]) b = char_d2r(labstart[lab][++lpos]); else { /* if last label, no match since * we are in the additional string */ if(lab == 0) return NULL; /* next label, search for byte 00 */ lpos = 0; lab--; b = 0; } if(n->array[byte].str[i] != b) return NULL; /* not matched */ } } n = n->array[byte].node; } return NULL; } /* find domain name or smaller or equal domain name in radix tree */ int radname_find_less_equal(struct radtree* rt, const uint8_t* d, size_t max, struct radnode** result) { /* stack of labels in the domain name */ const uint8_t* labstart[130]; unsigned int lab, dpos, lpos; struct radnode* n = rt->root; uint8_t byte; radstrlen_type i; uint8_t b; /* empty tree */ if(!n) { *result = NULL; return 0; } /* search for root? it is '' */ if(max < 1) { *result = NULL; return 0; /* parse error, out of bounds */ } if(d[0] == 0) { if(n->elem) { *result = n; return 1; } /* no smaller element than the root */ *result = NULL; return 0; } /* find labels stack in domain name */ lab = 0; dpos = 0; /* must have one label, since root is specialcased */ do { if((d[dpos] & 0xc0)) { *result = NULL; return 0; /* compression ptrs not allowed error */ } labstart[lab++] = &d[dpos]; if(dpos + d[dpos] + 1 >= max) { *result = NULL; /* format error: outside of bounds */ return 0; } /* skip the label contents */ dpos += d[dpos]; dpos ++; } while(d[dpos] != 0); /* exit condition makes that root label is not in the labstarts */ /* now: dpos+1 is length of domain name. lab is number of labels-1 */ /* start processing at the last label */ lab-=1; lpos = 0; while(1) { /* fetch next byte this label */ if(lpos < *labstart[lab]) /* lpos+1 to skip labelstart, lpos++ to move forward */ byte = char_d2r(labstart[lab][++lpos]); else { if(lab == 0) { /* last label - we're done */ /* exact match */ if(n->elem) { *result = n; return 1; } /* there is a node which is an exact match, * but there no element in it */ *result = radix_prev(n); return 0; } /* next label, search for byte 0 the label separator */ lpos = 0; lab--; byte = 0; } /* find that byte in the array */ if(byte < n->offset) /* so the previous is the element itself */ /* or something before this element */ return ret_self_or_prev(n, result); byte -= n->offset; if(byte >= n->len) { /* so, the previous is the last of array, or itself */ /* or something before this element */ *result = radnode_last_in_subtree_incl_self(n); if(!*result) *result = radix_prev(n); return 0; } if(!n->array[byte].node) { /* no match */ /* Find an entry in arrays from byte-1 to 0 */ *result = radnode_find_prev_from_idx(n, byte); if(*result) return 0; /* this entry or something before it */ return ret_self_or_prev(n, result); } if(n->array[byte].len != 0) { /* must match additional string */ /* see how many bytes we need and start matching them*/ for(i=0; iarray[byte].len; i++) { /* next byte to match */ if(lpos < *labstart[lab]) b = char_d2r(labstart[lab][++lpos]); else { /* if last label, no match since * we are in the additional string */ if(lab == 0) { /* dname ended, thus before * this array element */ *result =radix_prev( n->array[byte].node); return 0; } /* next label, search for byte 00 */ lpos = 0; lab--; b = 0; } if(b < n->array[byte].str[i]) { *result =radix_prev( n->array[byte].node); return 0; } else if(b > n->array[byte].str[i]) { /* the key is after the additional, * so everything in its subtree is * smaller */ *result = radnode_last_in_subtree_incl_self(n->array[byte].node); /* if that is NULL, we have an * inefficient tree, find in byte-1*/ if(!*result) *result = radix_prev(n->array[byte].node); return 0; } } } n = n->array[byte].node; } /* ENOTREACH */ return 0; } nsd-4.1.26/iterated_hash.h0000664000175000017500000000102711542151203014775 0ustar wouterwouter/* * iterated_hash.h -- nsec3 hash calculation. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * With thanks to Ben Laurie. */ #ifndef ITERATED_HASH_H #define ITERATED_HASH_H #ifdef NSEC3 #include #define NSEC3_SHA1_HASH 1 /* same type code as DS hash */ int iterated_hash(unsigned char out[SHA_DIGEST_LENGTH], const unsigned char *salt,int saltlength, const unsigned char *in,int inlength,int iterations); #endif /* NSEC3 */ #endif /* ITERATED_HASH_H */ nsd-4.1.26/configparser.c0000664000175000017500000032255113401455025014663 0ustar wouterwouter/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Copy the first part of user declarations. */ #line 10 "configparser.y" /* yacc.c:339 */ #include "config.h" #include #include #include #include #include #include "options.h" #include "util.h" #include "dname.h" #include "tsig.h" #include "rrl.h" #include "configyyrename.h" int c_lex(void); void c_error(const char *message); #ifdef __cplusplus extern "C" #endif /* __cplusplus */ /* these need to be global, otherwise they cannot be used inside yacc */ extern config_parser_state_type* cfg_parser; #if 0 #define OUTYY(s) printf s /* used ONLY when debugging */ #else #define OUTYY(s) #endif #line 99 "configparser.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "configparser.h". */ #ifndef YY_YY_CONFIGPARSER_H_INCLUDED # define YY_YY_CONFIGPARSER_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { SPACE = 258, LETTER = 259, NEWLINE = 260, COMMENT = 261, COLON = 262, ANY = 263, ZONESTR = 264, STRING = 265, VAR_SERVER = 266, VAR_NAME = 267, VAR_IP_ADDRESS = 268, VAR_IP_TRANSPARENT = 269, VAR_DEBUG_MODE = 270, VAR_IP4_ONLY = 271, VAR_IP6_ONLY = 272, VAR_DATABASE = 273, VAR_IDENTITY = 274, VAR_NSID = 275, VAR_LOGFILE = 276, VAR_SERVER_COUNT = 277, VAR_TCP_COUNT = 278, VAR_PIDFILE = 279, VAR_PORT = 280, VAR_STATISTICS = 281, VAR_CHROOT = 282, VAR_USERNAME = 283, VAR_ZONESDIR = 284, VAR_XFRDFILE = 285, VAR_DIFFFILE = 286, VAR_XFRD_RELOAD_TIMEOUT = 287, VAR_TCP_QUERY_COUNT = 288, VAR_TCP_TIMEOUT = 289, VAR_IPV4_EDNS_SIZE = 290, VAR_IPV6_EDNS_SIZE = 291, VAR_DO_IP4 = 292, VAR_DO_IP6 = 293, VAR_TCP_MSS = 294, VAR_OUTGOING_TCP_MSS = 295, VAR_IP_FREEBIND = 296, VAR_ZONEFILE = 297, VAR_ZONE = 298, VAR_ALLOW_NOTIFY = 299, VAR_REQUEST_XFR = 300, VAR_NOTIFY = 301, VAR_PROVIDE_XFR = 302, VAR_SIZE_LIMIT_XFR = 303, VAR_NOTIFY_RETRY = 304, VAR_OUTGOING_INTERFACE = 305, VAR_ALLOW_AXFR_FALLBACK = 306, VAR_KEY = 307, VAR_ALGORITHM = 308, VAR_SECRET = 309, VAR_AXFR = 310, VAR_UDP = 311, VAR_VERBOSITY = 312, VAR_HIDE_VERSION = 313, VAR_PATTERN = 314, VAR_INCLUDEPATTERN = 315, VAR_ZONELISTFILE = 316, VAR_REMOTE_CONTROL = 317, VAR_CONTROL_ENABLE = 318, VAR_CONTROL_INTERFACE = 319, VAR_CONTROL_PORT = 320, VAR_SERVER_KEY_FILE = 321, VAR_SERVER_CERT_FILE = 322, VAR_CONTROL_KEY_FILE = 323, VAR_CONTROL_CERT_FILE = 324, VAR_XFRDIR = 325, VAR_RRL_SIZE = 326, VAR_RRL_RATELIMIT = 327, VAR_RRL_SLIP = 328, VAR_RRL_IPV4_PREFIX_LENGTH = 329, VAR_RRL_IPV6_PREFIX_LENGTH = 330, VAR_RRL_WHITELIST_RATELIMIT = 331, VAR_RRL_WHITELIST = 332, VAR_ZONEFILES_CHECK = 333, VAR_ZONEFILES_WRITE = 334, VAR_LOG_TIME_ASCII = 335, VAR_ROUND_ROBIN = 336, VAR_ZONESTATS = 337, VAR_REUSEPORT = 338, VAR_VERSION = 339, VAR_MAX_REFRESH_TIME = 340, VAR_MIN_REFRESH_TIME = 341, VAR_MAX_RETRY_TIME = 342, VAR_MIN_RETRY_TIME = 343, VAR_MULTI_MASTER_CHECK = 344, VAR_MINIMAL_RESPONSES = 345, VAR_REFUSE_ANY = 346, VAR_USE_SYSTEMD = 347, VAR_DNSTAP = 348, VAR_DNSTAP_ENABLE = 349, VAR_DNSTAP_SOCKET_PATH = 350, VAR_DNSTAP_SEND_IDENTITY = 351, VAR_DNSTAP_SEND_VERSION = 352, VAR_DNSTAP_IDENTITY = 353, VAR_DNSTAP_VERSION = 354, VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES = 355, VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES = 356 }; #endif /* Tokens. */ #define SPACE 258 #define LETTER 259 #define NEWLINE 260 #define COMMENT 261 #define COLON 262 #define ANY 263 #define ZONESTR 264 #define STRING 265 #define VAR_SERVER 266 #define VAR_NAME 267 #define VAR_IP_ADDRESS 268 #define VAR_IP_TRANSPARENT 269 #define VAR_DEBUG_MODE 270 #define VAR_IP4_ONLY 271 #define VAR_IP6_ONLY 272 #define VAR_DATABASE 273 #define VAR_IDENTITY 274 #define VAR_NSID 275 #define VAR_LOGFILE 276 #define VAR_SERVER_COUNT 277 #define VAR_TCP_COUNT 278 #define VAR_PIDFILE 279 #define VAR_PORT 280 #define VAR_STATISTICS 281 #define VAR_CHROOT 282 #define VAR_USERNAME 283 #define VAR_ZONESDIR 284 #define VAR_XFRDFILE 285 #define VAR_DIFFFILE 286 #define VAR_XFRD_RELOAD_TIMEOUT 287 #define VAR_TCP_QUERY_COUNT 288 #define VAR_TCP_TIMEOUT 289 #define VAR_IPV4_EDNS_SIZE 290 #define VAR_IPV6_EDNS_SIZE 291 #define VAR_DO_IP4 292 #define VAR_DO_IP6 293 #define VAR_TCP_MSS 294 #define VAR_OUTGOING_TCP_MSS 295 #define VAR_IP_FREEBIND 296 #define VAR_ZONEFILE 297 #define VAR_ZONE 298 #define VAR_ALLOW_NOTIFY 299 #define VAR_REQUEST_XFR 300 #define VAR_NOTIFY 301 #define VAR_PROVIDE_XFR 302 #define VAR_SIZE_LIMIT_XFR 303 #define VAR_NOTIFY_RETRY 304 #define VAR_OUTGOING_INTERFACE 305 #define VAR_ALLOW_AXFR_FALLBACK 306 #define VAR_KEY 307 #define VAR_ALGORITHM 308 #define VAR_SECRET 309 #define VAR_AXFR 310 #define VAR_UDP 311 #define VAR_VERBOSITY 312 #define VAR_HIDE_VERSION 313 #define VAR_PATTERN 314 #define VAR_INCLUDEPATTERN 315 #define VAR_ZONELISTFILE 316 #define VAR_REMOTE_CONTROL 317 #define VAR_CONTROL_ENABLE 318 #define VAR_CONTROL_INTERFACE 319 #define VAR_CONTROL_PORT 320 #define VAR_SERVER_KEY_FILE 321 #define VAR_SERVER_CERT_FILE 322 #define VAR_CONTROL_KEY_FILE 323 #define VAR_CONTROL_CERT_FILE 324 #define VAR_XFRDIR 325 #define VAR_RRL_SIZE 326 #define VAR_RRL_RATELIMIT 327 #define VAR_RRL_SLIP 328 #define VAR_RRL_IPV4_PREFIX_LENGTH 329 #define VAR_RRL_IPV6_PREFIX_LENGTH 330 #define VAR_RRL_WHITELIST_RATELIMIT 331 #define VAR_RRL_WHITELIST 332 #define VAR_ZONEFILES_CHECK 333 #define VAR_ZONEFILES_WRITE 334 #define VAR_LOG_TIME_ASCII 335 #define VAR_ROUND_ROBIN 336 #define VAR_ZONESTATS 337 #define VAR_REUSEPORT 338 #define VAR_VERSION 339 #define VAR_MAX_REFRESH_TIME 340 #define VAR_MIN_REFRESH_TIME 341 #define VAR_MAX_RETRY_TIME 342 #define VAR_MIN_RETRY_TIME 343 #define VAR_MULTI_MASTER_CHECK 344 #define VAR_MINIMAL_RESPONSES 345 #define VAR_REFUSE_ANY 346 #define VAR_USE_SYSTEMD 347 #define VAR_DNSTAP 348 #define VAR_DNSTAP_ENABLE 349 #define VAR_DNSTAP_SOCKET_PATH 350 #define VAR_DNSTAP_SEND_IDENTITY 351 #define VAR_DNSTAP_SEND_VERSION 352 #define VAR_DNSTAP_IDENTITY 353 #define VAR_DNSTAP_VERSION 354 #define VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES 355 #define VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES 356 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 42 "configparser.y" /* yacc.c:355 */ char* str; #line 345 "configparser.c" /* yacc.c:355 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_CONFIGPARSER_H_INCLUDED */ /* Copy the second part of user declarations. */ #line 362 "configparser.c" /* yacc.c:358 */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 208 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 102 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 108 /* YYNRULES -- Number of rules. */ #define YYNRULES 202 /* YYNSTATES -- Number of states. */ #define YYNSTATES 299 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 356 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 81, 81, 81, 82, 82, 83, 83, 84, 84, 87, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 104, 104, 105, 105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 111, 133, 141, 149, 157, 162, 170, 178, 190, 202, 210, 218, 226, 235, 241, 247, 277, 283, 294, 305, 316, 326, 334, 342, 348, 354, 362, 368, 374, 380, 386, 392, 398, 404, 412, 420, 428, 436, 444, 452, 460, 470, 478, 488, 498, 508, 516, 524, 533, 538, 539, 540, 540, 540, 541, 541, 541, 542, 544, 552, 560, 577, 583, 589, 595, 603, 608, 609, 610, 610, 611, 611, 612, 612, 613, 614, 616, 624, 630, 638, 646, 652, 658, 666, 676, 710, 710, 711, 711, 712, 712, 712, 713, 713, 713, 714, 714, 714, 715, 715, 715, 716, 716, 716, 717, 717, 718, 730, 741, 778, 778, 779, 779, 780, 800, 809, 818, 829, 833, 841, 853, 866, 880, 893, 904, 915, 927, 938, 946, 956, 966, 976, 986, 995, 1008, 1008, 1009, 1009, 1009, 1010, 1024, 1037 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "SPACE", "LETTER", "NEWLINE", "COMMENT", "COLON", "ANY", "ZONESTR", "STRING", "VAR_SERVER", "VAR_NAME", "VAR_IP_ADDRESS", "VAR_IP_TRANSPARENT", "VAR_DEBUG_MODE", "VAR_IP4_ONLY", "VAR_IP6_ONLY", "VAR_DATABASE", "VAR_IDENTITY", "VAR_NSID", "VAR_LOGFILE", "VAR_SERVER_COUNT", "VAR_TCP_COUNT", "VAR_PIDFILE", "VAR_PORT", "VAR_STATISTICS", "VAR_CHROOT", "VAR_USERNAME", "VAR_ZONESDIR", "VAR_XFRDFILE", "VAR_DIFFFILE", "VAR_XFRD_RELOAD_TIMEOUT", "VAR_TCP_QUERY_COUNT", "VAR_TCP_TIMEOUT", "VAR_IPV4_EDNS_SIZE", "VAR_IPV6_EDNS_SIZE", "VAR_DO_IP4", "VAR_DO_IP6", "VAR_TCP_MSS", "VAR_OUTGOING_TCP_MSS", "VAR_IP_FREEBIND", "VAR_ZONEFILE", "VAR_ZONE", "VAR_ALLOW_NOTIFY", "VAR_REQUEST_XFR", "VAR_NOTIFY", "VAR_PROVIDE_XFR", "VAR_SIZE_LIMIT_XFR", "VAR_NOTIFY_RETRY", "VAR_OUTGOING_INTERFACE", "VAR_ALLOW_AXFR_FALLBACK", "VAR_KEY", "VAR_ALGORITHM", "VAR_SECRET", "VAR_AXFR", "VAR_UDP", "VAR_VERBOSITY", "VAR_HIDE_VERSION", "VAR_PATTERN", "VAR_INCLUDEPATTERN", "VAR_ZONELISTFILE", "VAR_REMOTE_CONTROL", "VAR_CONTROL_ENABLE", "VAR_CONTROL_INTERFACE", "VAR_CONTROL_PORT", "VAR_SERVER_KEY_FILE", "VAR_SERVER_CERT_FILE", "VAR_CONTROL_KEY_FILE", "VAR_CONTROL_CERT_FILE", "VAR_XFRDIR", "VAR_RRL_SIZE", "VAR_RRL_RATELIMIT", "VAR_RRL_SLIP", "VAR_RRL_IPV4_PREFIX_LENGTH", "VAR_RRL_IPV6_PREFIX_LENGTH", "VAR_RRL_WHITELIST_RATELIMIT", "VAR_RRL_WHITELIST", "VAR_ZONEFILES_CHECK", "VAR_ZONEFILES_WRITE", "VAR_LOG_TIME_ASCII", "VAR_ROUND_ROBIN", "VAR_ZONESTATS", "VAR_REUSEPORT", "VAR_VERSION", "VAR_MAX_REFRESH_TIME", "VAR_MIN_REFRESH_TIME", "VAR_MAX_RETRY_TIME", "VAR_MIN_RETRY_TIME", "VAR_MULTI_MASTER_CHECK", "VAR_MINIMAL_RESPONSES", "VAR_REFUSE_ANY", "VAR_USE_SYSTEMD", "VAR_DNSTAP", "VAR_DNSTAP_ENABLE", "VAR_DNSTAP_SOCKET_PATH", "VAR_DNSTAP_SEND_IDENTITY", "VAR_DNSTAP_SEND_VERSION", "VAR_DNSTAP_IDENTITY", "VAR_DNSTAP_VERSION", "VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES", "VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES", "$accept", "toplevelvars", "toplevelvar", "serverstart", "contents_server", "content_server", "server_ip_address", "server_ip_transparent", "server_ip_freebind", "server_debug_mode", "server_use_systemd", "server_verbosity", "server_hide_version", "server_ip4_only", "server_ip6_only", "server_do_ip4", "server_do_ip6", "server_reuseport", "server_database", "server_identity", "server_version", "server_nsid", "server_logfile", "server_log_time_ascii", "server_round_robin", "server_minimal_responses", "server_refuse_any", "server_server_count", "server_tcp_count", "server_pidfile", "server_port", "server_statistics", "server_chroot", "server_username", "server_zonesdir", "server_zonelistfile", "server_xfrdir", "server_difffile", "server_xfrdfile", "server_xfrd_reload_timeout", "server_tcp_query_count", "server_tcp_timeout", "server_tcp_mss", "server_outgoing_tcp_mss", "server_ipv4_edns_size", "server_ipv6_edns_size", "server_rrl_size", "server_rrl_ratelimit", "server_rrl_slip", "server_rrl_ipv4_prefix_length", "server_rrl_ipv6_prefix_length", "server_rrl_whitelist_ratelimit", "server_zonefiles_check", "server_zonefiles_write", "rcstart", "contents_rc", "content_rc", "rc_control_enable", "rc_control_port", "rc_control_interface", "rc_server_key_file", "rc_server_cert_file", "rc_control_key_file", "rc_control_cert_file", "dtstart", "contents_dt", "content_dt", "dt_dnstap_enable", "dt_dnstap_socket_path", "dt_dnstap_send_identity", "dt_dnstap_send_version", "dt_dnstap_identity", "dt_dnstap_version", "dt_dnstap_log_auth_query_messages", "dt_dnstap_log_auth_response_messages", "patternstart", "contents_pattern", "content_pattern", "zone_config_item", "pattern_name", "include_pattern", "zonestart", "contents_zone", "content_zone", "zone_name", "zone_zonefile", "zone_zonestats", "zone_allow_notify", "zone_request_xfr", "zone_size_limit_xfr", "zone_request_xfr_data", "zone_notify", "zone_notify_retry", "zone_provide_xfr", "zone_outgoing_interface", "zone_allow_axfr_fallback", "zone_rrl_whitelist", "zone_max_refresh_time", "zone_min_refresh_time", "zone_max_retry_time", "zone_min_retry_time", "zone_multi_master_check", "keystart", "contents_key", "content_key", "key_name", "key_algorithm", "key_secret", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356 }; # endif #define YYPACT_NINF -57 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-57))) #define YYTABLE_NINF -1 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { -57, 0, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 52, 72, -4, -1, 79, 10, -7, -6, -5, -9, -3, 31, 32, 34, 35, 41, 43, 44, 45, 48, 51, 53, 55, 56, 52, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 57, -57, 72, -57, -57, 58, 66, 71, -4, -57, -57, -57, -57, 75, 76, 77, 78, 82, 85, 103, 105, 114, 115, 116, 117, 118, 120, 121, 123, 125, 126, 140, 141, 142, 143, 145, 146, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 176, 177, 178, 179, 180, 181, 182, -57, -57, -57, -57, -57, -57, -57, -57, 183, 184, 185, 186, 187, 188, 189, 190, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 191, 192, 193, 194, -57, 195, 196, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, 197, 198, -57, -57, -57, -57 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 1, 10, 169, 194, 145, 109, 126, 3, 12, 111, 128, 0, 0, 0, 4, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 147, 149, 148, 158, 150, 160, 151, 152, 165, 153, 154, 155, 156, 157, 159, 161, 162, 163, 164, 166, 0, 173, 5, 171, 172, 0, 0, 0, 6, 196, 197, 198, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 13, 14, 57, 15, 60, 37, 38, 16, 17, 50, 51, 55, 18, 19, 56, 20, 21, 53, 54, 58, 59, 22, 23, 24, 25, 26, 27, 28, 29, 39, 40, 30, 31, 32, 33, 34, 41, 42, 35, 36, 43, 44, 45, 46, 47, 48, 49, 52, 0, 0, 0, 0, 0, 0, 0, 110, 112, 114, 113, 115, 116, 117, 118, 0, 0, 0, 0, 0, 0, 0, 0, 127, 129, 130, 131, 132, 133, 134, 135, 136, 167, 175, 0, 0, 0, 0, 178, 0, 0, 179, 184, 186, 187, 168, 188, 176, 189, 190, 191, 192, 193, 146, 174, 170, 200, 201, 202, 195, 61, 62, 64, 68, 69, 73, 74, 76, 77, 82, 83, 84, 85, 86, 87, 88, 89, 93, 92, 94, 95, 96, 99, 100, 70, 71, 97, 98, 63, 66, 67, 90, 91, 101, 102, 103, 104, 105, 106, 107, 108, 78, 79, 72, 75, 80, 81, 65, 119, 121, 120, 122, 123, 124, 125, 137, 138, 139, 140, 141, 142, 143, 144, 177, 180, 0, 0, 183, 185, 181, 182 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -31, -12, -57, -57, -57, -57, -51, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -56, -57, -57, -57 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 1, 9, 10, 16, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 11, 17, 175, 176, 177, 178, 179, 180, 181, 182, 12, 18, 191, 192, 193, 194, 195, 196, 197, 198, 199, 13, 37, 38, 39, 40, 41, 14, 60, 61, 62, 42, 43, 44, 45, 46, 206, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 15, 66, 67, 68, 69, 70 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint16 yytable[] = { 2, 203, 59, 200, 201, 202, 221, 207, 63, 223, 227, 3, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 208, 209, 4, 210, 211, 204, 205, 59, 64, 65, 212, 5, 213, 214, 215, 100, 101, 216, 6, 102, 217, 7, 218, 19, 219, 220, 222, 224, 103, 104, 105, 106, 107, 108, 109, 225, 110, 111, 112, 113, 226, 114, 115, 58, 228, 229, 230, 231, 116, 117, 118, 232, 8, 20, 233, 21, 22, 23, 24, 25, 26, 27, 28, 183, 184, 185, 186, 187, 188, 189, 190, 29, 234, 20, 235, 21, 22, 23, 24, 25, 26, 27, 28, 236, 237, 238, 239, 240, 30, 241, 242, 29, 243, 31, 244, 245, 32, 33, 34, 35, 36, 168, 169, 170, 171, 172, 173, 174, 30, 246, 247, 248, 249, 31, 250, 251, 32, 33, 34, 35, 36, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298 }; static const yytype_uint8 yycheck[] = { 0, 10, 14, 10, 10, 10, 37, 10, 12, 60, 66, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 10, 10, 43, 10, 10, 55, 56, 60, 53, 54, 10, 52, 10, 10, 10, 57, 58, 10, 59, 61, 10, 62, 10, 12, 10, 10, 10, 10, 70, 71, 72, 73, 74, 75, 76, 10, 78, 79, 80, 81, 10, 83, 84, 12, 10, 10, 10, 10, 90, 91, 92, 10, 93, 42, 10, 44, 45, 46, 47, 48, 49, 50, 51, 94, 95, 96, 97, 98, 99, 100, 101, 60, 10, 42, 10, 44, 45, 46, 47, 48, 49, 50, 51, 10, 10, 10, 10, 10, 77, 10, 10, 60, 10, 82, 10, 10, 85, 86, 87, 88, 89, 63, 64, 65, 66, 67, 68, 69, 77, 10, 10, 10, 10, 82, 10, 10, 85, 86, 87, 88, 89, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 103, 0, 11, 43, 52, 59, 62, 93, 104, 105, 156, 166, 177, 183, 204, 106, 157, 167, 12, 42, 44, 45, 46, 47, 48, 49, 50, 51, 60, 77, 82, 85, 86, 87, 88, 89, 178, 179, 180, 181, 182, 187, 188, 189, 190, 191, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 12, 180, 184, 185, 186, 12, 53, 54, 205, 206, 207, 208, 209, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 57, 58, 61, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, 81, 83, 84, 90, 91, 92, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 63, 64, 65, 66, 67, 68, 69, 158, 159, 160, 161, 162, 163, 164, 165, 94, 95, 96, 97, 98, 99, 100, 101, 168, 169, 170, 171, 172, 173, 174, 175, 176, 10, 10, 10, 10, 55, 56, 192, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 179, 10, 185, 10, 10, 10, 206, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 102, 103, 103, 104, 104, 104, 104, 104, 104, 105, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 157, 158, 158, 158, 158, 158, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, 179, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 182, 183, 184, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 206, 206, 207, 208, 209 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 3, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 2, 2, 2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) { unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 10: #line 88 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(server:)\n")); if(cfg_parser->server_settings_seen) { yyerror("duplicate server: element."); } cfg_parser->server_settings_seen = 1; } #line 1723 "configparser.c" /* yacc.c:1646 */ break; case 61: #line 112 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_ip_address:%s)\n", (yyvsp[0].str))); if(cfg_parser->current_ip_address_option) { cfg_parser->current_ip_address_option->next = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); cfg_parser->current_ip_address_option = cfg_parser->current_ip_address_option->next; cfg_parser->current_ip_address_option->next=0; } else { cfg_parser->current_ip_address_option = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); cfg_parser->current_ip_address_option->next=0; cfg_parser->opt->ip_addresses = cfg_parser->current_ip_address_option; } cfg_parser->current_ip_address_option->address = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1748 "configparser.c" /* yacc.c:1646 */ break; case 62: #line 134 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_ip_transparent:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->ip_transparent = (strcmp((yyvsp[0].str), "yes")==0); } #line 1759 "configparser.c" /* yacc.c:1646 */ break; case 63: #line 142 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_ip_freebind:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->ip_freebind = (strcmp((yyvsp[0].str), "yes")==0); } #line 1770 "configparser.c" /* yacc.c:1646 */ break; case 64: #line 150 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_debug_mode:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->debug_mode = (strcmp((yyvsp[0].str), "yes")==0); } #line 1781 "configparser.c" /* yacc.c:1646 */ break; case 65: #line 158 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_use_systemd:%s)\n", (yyvsp[0].str))); } #line 1789 "configparser.c" /* yacc.c:1646 */ break; case 66: #line 163 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_verbosity:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else cfg_parser->opt->verbosity = atoi((yyvsp[0].str)); } #line 1800 "configparser.c" /* yacc.c:1646 */ break; case 67: #line 171 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_hide_version:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->hide_version = (strcmp((yyvsp[0].str), "yes")==0); } #line 1811 "configparser.c" /* yacc.c:1646 */ break; case 68: #line 179 "configparser.y" /* yacc.c:1646 */ { /* for backwards compatibility in config file with NSD3 */ OUTYY(("P(server_ip4_only:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else if(strcmp((yyvsp[0].str), "yes")==0) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } } #line 1826 "configparser.c" /* yacc.c:1646 */ break; case 69: #line 191 "configparser.y" /* yacc.c:1646 */ { /* for backwards compatibility in config file with NSD3 */ OUTYY(("P(server_ip6_only:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else if(strcmp((yyvsp[0].str), "yes")==0) { cfg_parser->opt->do_ip6 = 1; cfg_parser->opt->do_ip4 = 0; } } #line 1841 "configparser.c" /* yacc.c:1646 */ break; case 70: #line 203 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_do_ip4:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->do_ip4 = (strcmp((yyvsp[0].str), "yes")==0); } #line 1852 "configparser.c" /* yacc.c:1646 */ break; case 71: #line 211 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_do_ip6:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->do_ip6 = (strcmp((yyvsp[0].str), "yes")==0); } #line 1863 "configparser.c" /* yacc.c:1646 */ break; case 72: #line 219 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_reuseport:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->reuseport = (strcmp((yyvsp[0].str), "yes")==0); } #line 1874 "configparser.c" /* yacc.c:1646 */ break; case 73: #line 227 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_database:%s)\n", (yyvsp[0].str))); cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if(cfg_parser->opt->database[0] == 0 && cfg_parser->opt->zonefiles_write == 0) cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; } #line 1886 "configparser.c" /* yacc.c:1646 */ break; case 74: #line 236 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_identity:%s)\n", (yyvsp[0].str))); cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1895 "configparser.c" /* yacc.c:1646 */ break; case 75: #line 242 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_version:%s)\n", (yyvsp[0].str))); cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1904 "configparser.c" /* yacc.c:1646 */ break; case 76: #line 248 "configparser.y" /* yacc.c:1646 */ { unsigned char* nsid = 0; size_t nsid_len = 0; OUTYY(("P(server_nsid:%s)\n", (yyvsp[0].str))); if (strncasecmp((yyvsp[0].str), "ascii_", 6) == 0) { nsid_len = strlen((yyvsp[0].str)+6); if(nsid_len < 65535) { cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); hex_ntop((uint8_t*)(yyvsp[0].str)+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); } else yyerror("NSID too long"); } else if (strlen((yyvsp[0].str)) % 2 != 0) { yyerror("the NSID must be a hex string of an even length."); } else { nsid_len = strlen((yyvsp[0].str)) / 2; if(nsid_len < 65535) { nsid = xalloc(nsid_len); if (hex_pton((yyvsp[0].str), nsid, nsid_len) == -1) yyerror("hex string cannot be parsed in NSID."); else cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); free(nsid); } else yyerror("NSID too long"); } } #line 1937 "configparser.c" /* yacc.c:1646 */ break; case 77: #line 278 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_logfile:%s)\n", (yyvsp[0].str))); cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 1946 "configparser.c" /* yacc.c:1646 */ break; case 78: #line 284 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_log_time_ascii:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->log_time_ascii = (strcmp((yyvsp[0].str), "yes")==0); log_time_asc = cfg_parser->opt->log_time_ascii; } } #line 1960 "configparser.c" /* yacc.c:1646 */ break; case 79: #line 295 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_round_robin:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->round_robin = (strcmp((yyvsp[0].str), "yes")==0); round_robin = cfg_parser->opt->round_robin; } } #line 1974 "configparser.c" /* yacc.c:1646 */ break; case 80: #line 306 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_minimal_responses:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->minimal_responses = (strcmp((yyvsp[0].str), "yes")==0); minimal_responses = cfg_parser->opt->minimal_responses; } } #line 1988 "configparser.c" /* yacc.c:1646 */ break; case 81: #line 317 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_refuse_any:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else { cfg_parser->opt->refuse_any = (strcmp((yyvsp[0].str), "yes")==0); } } #line 2001 "configparser.c" /* yacc.c:1646 */ break; case 82: #line 327 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_server_count:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) <= 0) yyerror("number greater than zero expected"); else cfg_parser->opt->server_count = atoi((yyvsp[0].str)); } #line 2012 "configparser.c" /* yacc.c:1646 */ break; case 83: #line 335 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_tcp_count:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) <= 0) yyerror("number greater than zero expected"); else cfg_parser->opt->tcp_count = atoi((yyvsp[0].str)); } #line 2023 "configparser.c" /* yacc.c:1646 */ break; case 84: #line 343 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_pidfile:%s)\n", (yyvsp[0].str))); cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2032 "configparser.c" /* yacc.c:1646 */ break; case 85: #line 349 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_port:%s)\n", (yyvsp[0].str))); cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2041 "configparser.c" /* yacc.c:1646 */ break; case 86: #line 355 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_statistics:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else cfg_parser->opt->statistics = atoi((yyvsp[0].str)); } #line 2052 "configparser.c" /* yacc.c:1646 */ break; case 87: #line 363 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_chroot:%s)\n", (yyvsp[0].str))); cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2061 "configparser.c" /* yacc.c:1646 */ break; case 88: #line 369 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_username:%s)\n", (yyvsp[0].str))); cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2070 "configparser.c" /* yacc.c:1646 */ break; case 89: #line 375 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_zonesdir:%s)\n", (yyvsp[0].str))); cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2079 "configparser.c" /* yacc.c:1646 */ break; case 90: #line 381 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_zonelistfile:%s)\n", (yyvsp[0].str))); cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2088 "configparser.c" /* yacc.c:1646 */ break; case 91: #line 387 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_xfrdir:%s)\n", (yyvsp[0].str))); cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2097 "configparser.c" /* yacc.c:1646 */ break; case 92: #line 393 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_difffile:%s)\n", (yyvsp[0].str))); /* ignore the value for backwards compatibility in config file*/ } #line 2106 "configparser.c" /* yacc.c:1646 */ break; case 93: #line 399 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_xfrdfile:%s)\n", (yyvsp[0].str))); cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2115 "configparser.c" /* yacc.c:1646 */ break; case 94: #line 405 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_xfrd_reload_timeout:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->xfrd_reload_timeout = atoi((yyvsp[0].str)); } #line 2126 "configparser.c" /* yacc.c:1646 */ break; case 95: #line 413 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_tcp_query_count:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_query_count = atoi((yyvsp[0].str)); } #line 2137 "configparser.c" /* yacc.c:1646 */ break; case 96: #line 421 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_tcp_timeout:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_timeout = atoi((yyvsp[0].str)); } #line 2148 "configparser.c" /* yacc.c:1646 */ break; case 97: #line 429 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_tcp_mss:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->tcp_mss = atoi((yyvsp[0].str)); } #line 2159 "configparser.c" /* yacc.c:1646 */ break; case 98: #line 437 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_outgoing_tcp_mss:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->outgoing_tcp_mss = atoi((yyvsp[0].str)); } #line 2170 "configparser.c" /* yacc.c:1646 */ break; case 99: #line 445 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_ipv4_edns_size:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->ipv4_edns_size = atoi((yyvsp[0].str)); } #line 2181 "configparser.c" /* yacc.c:1646 */ break; case 100: #line 453 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_ipv6_edns_size:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); cfg_parser->opt->ipv6_edns_size = atoi((yyvsp[0].str)); } #line 2192 "configparser.c" /* yacc.c:1646 */ break; case 101: #line 461 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_size:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT if(atoi((yyvsp[0].str)) <= 0) yyerror("number greater than zero expected"); cfg_parser->opt->rrl_size = atoi((yyvsp[0].str)); #endif } #line 2205 "configparser.c" /* yacc.c:1646 */ break; case 102: #line 471 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_ratelimit:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT cfg_parser->opt->rrl_ratelimit = atoi((yyvsp[0].str)); #endif } #line 2216 "configparser.c" /* yacc.c:1646 */ break; case 103: #line 479 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_slip:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT if(atoi((yyvsp[0].str)) < 0) yyerror("number equal or greater than zero expected"); cfg_parser->opt->rrl_slip = atoi((yyvsp[0].str)); #endif } #line 2229 "configparser.c" /* yacc.c:1646 */ break; case 104: #line 489 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_ipv4_prefix_length:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT if(atoi((yyvsp[0].str)) < 0 || atoi((yyvsp[0].str)) > 32) yyerror("invalid IPv4 prefix length"); cfg_parser->opt->rrl_ipv4_prefix_length = atoi((yyvsp[0].str)); #endif } #line 2242 "configparser.c" /* yacc.c:1646 */ break; case 105: #line 499 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_ipv6_prefix_length:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT if(atoi((yyvsp[0].str)) < 0 || atoi((yyvsp[0].str)) > 64) yyerror("invalid IPv6 prefix length"); cfg_parser->opt->rrl_ipv6_prefix_length = atoi((yyvsp[0].str)); #endif } #line 2255 "configparser.c" /* yacc.c:1646 */ break; case 106: #line 509 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_rrl_whitelist_ratelimit:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT cfg_parser->opt->rrl_whitelist_ratelimit = atoi((yyvsp[0].str)); #endif } #line 2266 "configparser.c" /* yacc.c:1646 */ break; case 107: #line 517 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_zonefiles_check:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->zonefiles_check = (strcmp((yyvsp[0].str), "yes")==0); } #line 2277 "configparser.c" /* yacc.c:1646 */ break; case 108: #line 525 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(server_zonefiles_write:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else cfg_parser->opt->zonefiles_write = atoi((yyvsp[0].str)); } #line 2288 "configparser.c" /* yacc.c:1646 */ break; case 109: #line 534 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(remote-control:)\n")); } #line 2296 "configparser.c" /* yacc.c:1646 */ break; case 119: #line 545 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(control_enable:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->control_enable = (strcmp((yyvsp[0].str), "yes")==0); } #line 2307 "configparser.c" /* yacc.c:1646 */ break; case 120: #line 553 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(control_port:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0) yyerror("control port number expected"); else cfg_parser->opt->control_port = atoi((yyvsp[0].str)); } #line 2318 "configparser.c" /* yacc.c:1646 */ break; case 121: #line 561 "configparser.y" /* yacc.c:1646 */ { ip_address_option_type* last = NULL; ip_address_option_type* o = (ip_address_option_type*)region_alloc( cfg_parser->opt->region, sizeof(ip_address_option_type)); OUTYY(("P(control_interface:%s)\n", (yyvsp[0].str))); /* append at end */ last = cfg_parser->opt->control_interface; while(last && last->next) last = last->next; if(last == NULL) cfg_parser->opt->control_interface = o; else last->next = o; o->next = NULL; o->address = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2338 "configparser.c" /* yacc.c:1646 */ break; case 122: #line 578 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(rc_server_key_file:%s)\n", (yyvsp[0].str))); cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2347 "configparser.c" /* yacc.c:1646 */ break; case 123: #line 584 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(rc_server_cert_file:%s)\n", (yyvsp[0].str))); cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2356 "configparser.c" /* yacc.c:1646 */ break; case 124: #line 590 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(rc_control_key_file:%s)\n", (yyvsp[0].str))); cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2365 "configparser.c" /* yacc.c:1646 */ break; case 125: #line 596 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(rc_control_cert_file:%s)\n", (yyvsp[0].str))); cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2374 "configparser.c" /* yacc.c:1646 */ break; case 126: #line 604 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(dnstap:)\n")); } #line 2382 "configparser.c" /* yacc.c:1646 */ break; case 137: #line 617 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_enable:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_enable = (strcmp((yyvsp[0].str), "yes")==0); } #line 2393 "configparser.c" /* yacc.c:1646 */ break; case 138: #line 625 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_socket_path:%s)\n", (yyvsp[0].str))); cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2402 "configparser.c" /* yacc.c:1646 */ break; case 139: #line 631 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_send_identity:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_send_identity = (strcmp((yyvsp[0].str), "yes")==0); } #line 2413 "configparser.c" /* yacc.c:1646 */ break; case 140: #line 639 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_send_version:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_send_version = (strcmp((yyvsp[0].str), "yes")==0); } #line 2424 "configparser.c" /* yacc.c:1646 */ break; case 141: #line 647 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_identity:%s)\n", (yyvsp[0].str))); cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2433 "configparser.c" /* yacc.c:1646 */ break; case 142: #line 653 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_version:%s)\n", (yyvsp[0].str))); cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2442 "configparser.c" /* yacc.c:1646 */ break; case 143: #line 659 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_log_auth_query_messages:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_log_auth_query_messages = (strcmp((yyvsp[0].str), "yes")==0); } #line 2453 "configparser.c" /* yacc.c:1646 */ break; case 144: #line 667 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(dt_dnstap_log_auth_response_messages:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->dnstap_log_auth_response_messages = (strcmp((yyvsp[0].str), "yes")==0); } #line 2464 "configparser.c" /* yacc.c:1646 */ break; case 145: #line 677 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(pattern:)\n")); if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("previous zone has no name"); else { if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->current_zone)) c_error("duplicate zone"); } if(!cfg_parser->current_zone->pattern) c_error("previous zone has no pattern"); cfg_parser->current_zone = NULL; } if(cfg_parser->current_pattern) { if(!cfg_parser->current_pattern->pname) c_error("previous pattern has no name"); else { if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->current_pattern)) c_error_msg("duplicate pattern %s", cfg_parser->current_pattern->pname); } } cfg_parser->current_pattern = pattern_options_create( cfg_parser->opt->region); cfg_parser->current_allow_notify = 0; cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; cfg_parser->current_outgoing_interface = 0; } #line 2501 "configparser.c" /* yacc.c:1646 */ break; case 167: #line 719 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(pattern_name:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif if(strchr((yyvsp[0].str), ' ')) c_error_msg("space is not allowed in pattern name: " "'%s'", (yyvsp[0].str)); cfg_parser->current_pattern->pname = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2516 "configparser.c" /* yacc.c:1646 */ break; case 168: #line 731 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(include-pattern:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif config_apply_pattern((yyvsp[0].str)); } #line 2528 "configparser.c" /* yacc.c:1646 */ break; case 169: #line 742 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(zone:)\n")); if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("previous zone has no name"); else { if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->current_zone)) c_error("duplicate zone"); } if(!cfg_parser->current_zone->pattern) c_error("previous zone has no pattern"); } if(cfg_parser->current_pattern) { if(!cfg_parser->current_pattern->pname) c_error("previous pattern has no name"); else { if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->current_pattern)) c_error_msg("duplicate pattern %s", cfg_parser->current_pattern->pname); } } cfg_parser->current_zone = zone_options_create(cfg_parser->opt->region); cfg_parser->current_zone->part_of_config = 1; cfg_parser->current_pattern = pattern_options_create( cfg_parser->opt->region); cfg_parser->current_pattern->implicit = 1; cfg_parser->current_zone->pattern = cfg_parser->current_pattern; cfg_parser->current_allow_notify = 0; cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; cfg_parser->current_outgoing_interface = 0; } #line 2568 "configparser.c" /* yacc.c:1646 */ break; case 174: #line 781 "configparser.y" /* yacc.c:1646 */ { char* s; OUTYY(("P(zone_name:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_zone); assert(cfg_parser->current_pattern); #endif cfg_parser->current_zone->name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); s = (char*)region_alloc(cfg_parser->opt->region, strlen((yyvsp[0].str))+strlen(PATTERN_IMPLICIT_MARKER)+1); memmove(s, PATTERN_IMPLICIT_MARKER, strlen(PATTERN_IMPLICIT_MARKER)); memmove(s+strlen(PATTERN_IMPLICIT_MARKER), (yyvsp[0].str), strlen((yyvsp[0].str))+1); if(pattern_options_find(cfg_parser->opt, s)) c_error_msg("zone %s cannot be created because " "implicit pattern %s already exists", (yyvsp[0].str), s); cfg_parser->current_pattern->pname = s; } #line 2591 "configparser.c" /* yacc.c:1646 */ break; case 175: #line 801 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zonefile:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif cfg_parser->current_pattern->zonefile = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2603 "configparser.c" /* yacc.c:1646 */ break; case 176: #line 810 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zonestats:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_pattern); #endif cfg_parser->current_pattern->zonestats = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); } #line 2615 "configparser.c" /* yacc.c:1646 */ break; case 177: #line 819 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); OUTYY(("P(allow_notify:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(cfg_parser->current_allow_notify) cfg_parser->current_allow_notify->next = acl; else cfg_parser->current_pattern->allow_notify = acl; cfg_parser->current_allow_notify = acl; } #line 2629 "configparser.c" /* yacc.c:1646 */ break; case 178: #line 830 "configparser.y" /* yacc.c:1646 */ { } #line 2636 "configparser.c" /* yacc.c:1646 */ break; case 179: #line 834 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(size_limit_xfr:%s)\n", (yyvsp[0].str))); if(atoll((yyvsp[0].str)) < 0) yyerror("number >= 0 expected"); else cfg_parser->current_pattern->size_limit_xfr = atoll((yyvsp[0].str)); } #line 2647 "configparser.c" /* yacc.c:1646 */ break; case 180: #line 842 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); OUTYY(("P(request_xfr:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } #line 2663 "configparser.c" /* yacc.c:1646 */ break; case 181: #line 854 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); acl->use_axfr_only = 1; OUTYY(("P(request_xfr:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } #line 2680 "configparser.c" /* yacc.c:1646 */ break; case 182: #line 867 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); acl->allow_udp = 1; OUTYY(("P(request_xfr:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(acl->blocked) c_error("blocked address used for request-xfr"); if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr"); if(cfg_parser->current_request_xfr) cfg_parser->current_request_xfr->next = acl; else cfg_parser->current_pattern->request_xfr = acl; cfg_parser->current_request_xfr = acl; } #line 2697 "configparser.c" /* yacc.c:1646 */ break; case 183: #line 881 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); OUTYY(("P(notify:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(acl->blocked) c_error("blocked address used for notify"); if(acl->rangetype!=acl_range_single) c_error("address range used for notify"); if(cfg_parser->current_notify) cfg_parser->current_notify->next = acl; else cfg_parser->current_pattern->notify = acl; cfg_parser->current_notify = acl; } #line 2713 "configparser.c" /* yacc.c:1646 */ break; case 184: #line 894 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(notify_retry:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->notify_retry = atoi((yyvsp[0].str)); cfg_parser->current_pattern->notify_retry_is_default=0; } } #line 2727 "configparser.c" /* yacc.c:1646 */ break; case 185: #line 905 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[-1].str), (yyvsp[0].str)); OUTYY(("P(provide_xfr:%s %s)\n", (yyvsp[-1].str), (yyvsp[0].str))); if(cfg_parser->current_provide_xfr) cfg_parser->current_provide_xfr->next = acl; else cfg_parser->current_pattern->provide_xfr = acl; cfg_parser->current_provide_xfr = acl; } #line 2741 "configparser.c" /* yacc.c:1646 */ break; case 186: #line 916 "configparser.y" /* yacc.c:1646 */ { acl_options_type* acl = parse_acl_info(cfg_parser->opt->region, (yyvsp[0].str), "NOKEY"); OUTYY(("P(outgoing_interface:%s)\n", (yyvsp[0].str))); if(acl->rangetype!=acl_range_single) c_error("address range used for outgoing interface"); if(cfg_parser->current_outgoing_interface) cfg_parser->current_outgoing_interface->next = acl; else cfg_parser->current_pattern->outgoing_interface = acl; cfg_parser->current_outgoing_interface = acl; } #line 2756 "configparser.c" /* yacc.c:1646 */ break; case 187: #line 928 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(allow_axfr_fallback:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else { cfg_parser->current_pattern->allow_axfr_fallback = (strcmp((yyvsp[0].str), "yes")==0); cfg_parser->current_pattern->allow_axfr_fallback_is_default = 0; } } #line 2770 "configparser.c" /* yacc.c:1646 */ break; case 188: #line 939 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_rrl_whitelist:%s)\n", (yyvsp[0].str))); #ifdef RATELIMIT cfg_parser->current_pattern->rrl_whitelist |= rrlstr2type((yyvsp[0].str)); #endif } #line 2781 "configparser.c" /* yacc.c:1646 */ break; case 189: #line 947 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_max_refresh_time:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->max_refresh_time = atoi((yyvsp[0].str)); cfg_parser->current_pattern->max_refresh_time_is_default = 0; } } #line 2795 "configparser.c" /* yacc.c:1646 */ break; case 190: #line 957 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_min_refresh_time:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->min_refresh_time = atoi((yyvsp[0].str)); cfg_parser->current_pattern->min_refresh_time_is_default = 0; } } #line 2809 "configparser.c" /* yacc.c:1646 */ break; case 191: #line 967 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_max_retry_time:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->max_retry_time = atoi((yyvsp[0].str)); cfg_parser->current_pattern->max_retry_time_is_default = 0; } } #line 2823 "configparser.c" /* yacc.c:1646 */ break; case 192: #line 977 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_min_retry_time:%s)\n", (yyvsp[0].str))); if(atoi((yyvsp[0].str)) == 0 && strcmp((yyvsp[0].str), "0") != 0) yyerror("number expected"); else { cfg_parser->current_pattern->min_retry_time = atoi((yyvsp[0].str)); cfg_parser->current_pattern->min_retry_time_is_default = 0; } } #line 2837 "configparser.c" /* yacc.c:1646 */ break; case 193: #line 987 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(zone_multi_master_check:%s)\n", (yyvsp[0].str))); if(strcmp((yyvsp[0].str), "yes") != 0 && strcmp((yyvsp[0].str), "no") != 0) yyerror("expected yes or no."); else cfg_parser->current_pattern->multi_master_check = (strcmp((yyvsp[0].str), "yes")==0); } #line 2848 "configparser.c" /* yacc.c:1646 */ break; case 194: #line 996 "configparser.y" /* yacc.c:1646 */ { OUTYY(("\nP(key:)\n")); if(cfg_parser->current_key) { if(!cfg_parser->current_key->name) c_error("previous key has no name"); if(!cfg_parser->current_key->algorithm) c_error("previous key has no algorithm"); if(!cfg_parser->current_key->secret) c_error("previous key has no secret blob"); key_options_insert(cfg_parser->opt, cfg_parser->current_key); } cfg_parser->current_key = key_options_create(cfg_parser->opt->region); cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, "sha256"); } #line 2864 "configparser.c" /* yacc.c:1646 */ break; case 200: #line 1011 "configparser.y" /* yacc.c:1646 */ { const dname_type* d; OUTYY(("P(key_name:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_key); #endif cfg_parser->current_key->name = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); d = dname_parse(cfg_parser->opt->region, (yyvsp[0].str)); if(!d) c_error_msg("Failed to parse tsig key name %s", (yyvsp[0].str)); else region_recycle(cfg_parser->opt->region, (void*)d, dname_total_size(d)); } #line 2881 "configparser.c" /* yacc.c:1646 */ break; case 201: #line 1025 "configparser.y" /* yacc.c:1646 */ { OUTYY(("P(key_algorithm:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_key); #endif if(cfg_parser->current_key->algorithm) region_recycle(cfg_parser->opt->region, cfg_parser->current_key->algorithm, strlen(cfg_parser->current_key->algorithm)+1); cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); if(tsig_get_algorithm_by_name((yyvsp[0].str)) == NULL) c_error_msg("Bad tsig algorithm %s", (yyvsp[0].str)); } #line 2897 "configparser.c" /* yacc.c:1646 */ break; case 202: #line 1038 "configparser.y" /* yacc.c:1646 */ { uint8_t data[16384]; int size; OUTYY(("key_secret:%s)\n", (yyvsp[0].str))); #ifndef NDEBUG assert(cfg_parser->current_key); #endif cfg_parser->current_key->secret = region_strdup(cfg_parser->opt->region, (yyvsp[0].str)); size = b64_pton((yyvsp[0].str), data, sizeof(data)); if(size == -1) { c_error_msg("Cannot base64 decode tsig secret %s", cfg_parser->current_key->name? cfg_parser->current_key->name:""); } else if(size != 0) { memset(data, 0xdd, size); /* wipe secret */ } } #line 2919 "configparser.c" /* yacc.c:1646 */ break; #line 2923 "configparser.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 1057 "configparser.y" /* yacc.c:1906 */ /* parse helper routines could be here */ nsd-4.1.26/tsig-openssl.h0000664000175000017500000000077011406375413014636 0ustar wouterwouter/* * tsig-openssl.h -- Interface to OpenSSL for TSIG support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _TSIG_OPENSSL_H_ #define _TSIG_OPENSSL_H_ #if defined(HAVE_SSL) #include "region-allocator.h" #include #include /* * Initialize OpenSSL support for TSIG. */ int tsig_openssl_init(region_type *region); void tsig_openssl_finalize(); #endif /* defined(HAVE_SSL) */ #endif /* _TSIG_H_ */ nsd-4.1.26/buffer.c0000664000175000017500000000522311542151203013437 0ustar wouterwouter/* * buffer.c -- generic memory buffer . * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "buffer.h" static void buffer_cleanup(void *arg) { buffer_type *buffer = (buffer_type *) arg; assert(!buffer->_fixed); free(buffer->_data); } buffer_type * buffer_create(region_type *region, size_t capacity) { buffer_type *buffer = (buffer_type *) region_alloc(region, sizeof(buffer_type)); if (!buffer) return NULL; buffer->_data = (uint8_t *) xalloc(capacity); buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; buffer_invariant(buffer); region_add_cleanup(region, buffer_cleanup, buffer); return buffer; } void buffer_create_from(buffer_type *buffer, void *data, size_t size) { assert(data); buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_data = (uint8_t *) data; buffer->_fixed = 1; buffer_invariant(buffer); } void buffer_clear(buffer_type *buffer) { buffer_invariant(buffer); buffer->_position = 0; buffer->_limit = buffer->_capacity; } void buffer_flip(buffer_type *buffer) { buffer_invariant(buffer); buffer->_limit = buffer->_position; buffer->_position = 0; } void buffer_rewind(buffer_type *buffer) { buffer_invariant(buffer); buffer->_position = 0; } void buffer_set_capacity(buffer_type *buffer, size_t capacity) { buffer_invariant(buffer); assert(buffer->_position <= capacity); buffer->_data = (uint8_t *) xrealloc(buffer->_data, capacity); buffer->_limit = buffer->_capacity = capacity; } void buffer_reserve(buffer_type *buffer, size_t amount) { buffer_invariant(buffer); assert(!buffer->_fixed); if (buffer->_capacity < buffer->_position + amount) { size_t new_capacity = buffer->_capacity * 3 / 2; if (new_capacity < buffer->_position + amount) { new_capacity = buffer->_position + amount; } buffer_set_capacity(buffer, new_capacity); } buffer->_limit = buffer->_capacity; } int buffer_printf(buffer_type *buffer, const char *format, ...) { va_list args; int written; size_t remaining; buffer_invariant(buffer); assert(buffer->_limit == buffer->_capacity); remaining = buffer_remaining(buffer); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), remaining, format, args); va_end(args); if (written >= 0 && (size_t) written >= remaining) { buffer_reserve(buffer, written + 1); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), buffer_remaining(buffer), format, args); va_end(args); } buffer->_position += written; return written; } nsd-4.1.26/systemd.m40000664000175000017500000000210713314402317013756 0ustar wouterwouter# macros for configuring systemd # Copyright 2015, Sami Kerola, CloudFlare. # BSD licensed. AC_ARG_ENABLE([systemd], [AS_HELP_STRING([--enable-systemd], [compile with systemd support])], [], [enable_systemd=no]) have_systemd=no AS_IF([test "x$enable_systemd" != xno], [ ifdef([PKG_CHECK_MODULES], [ dnl systemd v209 or newer PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [have_systemd=yes], [have_systemd=no]) dnl old systemd library AS_IF([test "x$have_systemd" != "xyes"], [ PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon], [have_systemd_daemon=yes], [have_systemd_daemon=no]) AS_IF([test "x$have_systemd_daemon" = "xyes"], [have_systemd=yes]) ]) AS_CASE([$enable_systemd:$have_systemd], [yes:no], [AC_MSG_ERROR([systemd enabled but libsystemd not found])], [*:yes], [AC_DEFINE([HAVE_SYSTEMD], [1], [Define to 1 if systemd should be used]) LIBS="$LIBS $SYSTEMD_LIBS" ] ) ], [ AC_MSG_ERROR([systemd enabled but need pkg-config to configure for it, also, run aclocal before autoconf, or run autoreconf to include pkgconfig macros]) ]) ]) nsd-4.1.26/contrib/0000775000175000017500000000000013401455021013461 5ustar wouterwouternsd-4.1.26/contrib/bind2nsd/0000775000175000017500000000000013401455021015164 5ustar wouterwouternsd-4.1.26/contrib/bind2nsd/scripts/0000775000175000017500000000000013401455021016653 5ustar wouterwouternsd-4.1.26/contrib/bind2nsd/scripts/bind2nsd0000664000175000017500000000641010651575270020317 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # Convert a BIND named.conf file to an NSD nsd.conf file # #-- imports import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from NamedConf import * from NsdConf import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * from bind2nsd.Utils import * #-- globals conf = Config() DEBUG = conf.getValue('DEBUG') #-- utility functions def usage(): print 'bind2nsd %s -- Copyright (c) 2007 Secure64 Software Corporation.' % \ (conf.getValue('version')) print 'usage: bind2nsd' print ' all options are controlled by the config file' return #-- main starts here ---------------------------------------------- if len(sys.argv) > 2: usage() sys.exit(1) elif len(sys.argv) == 2 and sys.argv[1] == '-v': set_verbosity(True) #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? er, cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) if DEBUG: named.dump() os.chdir(pwd) #-- open the nsd.conf file and write out the translated version, including # all of the zone files needed. note that we're stashing everything in # the tmpdir as if it were a chroot dir (it simplifies the copy to our # server later on. # # FIXME: this is not multi-user safe -- if someone runs two copies # with the same tmpdir, we're hosed # pwd = os.getcwd() tmpdir = conf.getValue('tmpdir') if not os.path.exists(tmpdir): os.makedirs(tmpdir) os.chdir(tmpdir) nsd_fname = conf.getValue('nsd_conf') report_info('=> writing translated configuration to \"%s\"...' % (nsd_fname)) nsd = NsdConf(conf) nsd.populate(named) if DEBUG: nsd.dump() nsd.write_conf() report_info('=> writing zone files to \"%s\"...' % (tmpdir)) nsd.write_zone_files() os.chdir(pwd) #-- all done sys.exit(0) nsd-4.1.26/contrib/bind2nsd/scripts/nsd-sync0000664000175000017500000002604012623035675020354 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # When named.conf changes, update the NSD machine # # #-- imports import getopt import os import os.path import popen2 import re import sys import time if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from NamedConf import * from NsdConf import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * from bind2nsd.Utils import * if os.path.exists('../pexpect-2.1'): sys.path.append('../pexpect-2.1') import pexpect import pxssh #-- globals conf = Config() #-- useful functions def usage(): print 'nsd-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: nsd-sync [-a|--analyze-only] [-h|--help] [-s|--sync-only]' print ' [-n|--now]' print ' -a | --analyze-only => look for and report errors, but do' print ' not sync with the NSD server' print ' -h | --help => print this message and quit' print ' -n | --now => do not poll, sync immediately' print ' -s | --sync-only => sync without translating BIND files' print ' -v | --verbose => output lots of info' return def rebuild_nsd_files(): result = False xlate = conf.getValue('bind2nsd') if os.path.exists(xlate): result = run_cmd(xlate, 'running bind2nsd...') else: report_error('? could not find "%s" and have got to have it' % (xlate)) report_error(' skipping rebuild of NSD files') return result def scp_target(): #-- do the scp to an actual NSD server report_info('=> using scp to transfer to NSD system...') tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- this feels a bit dodgy due to issues in pexpect when it goes # up against passwd and other such nastiness from scp/ssh -- all # we should have to do is child.wait() really, but that does not # work as it should. # # NB: it turn out that you can _not_ put a '*' at the end of the # source path; pexpect.spawn() screws up and the parsing of the string # and ends up ignoring everything up to the '*', meaning the command # does not have the 'scp' part in it and does not get executed properly. # pwd = os.getcwd() os.chdir(tmpdir) flist = os.listdir('.') fnames = ' '.join(flist) cmd = 'scp -r ' + fnames cmd += ' ' + conf.getValue('destuser') + '@' cmd += conf.getValue('dest-ip') + ':' report_info('=> ' + cmd) child = pexpect.spawn(cmd) if len(conf.getValue('dnspw')) > 0: child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('.*' + conf.getValue('nsd_conf') + '.*') child.expect(pexpect.EOF) child.close() os.chdir(pwd) return def cp_files(analyze): #-- we assume everything has already been copied to the tmpdir by bind2nsd if analyze: return tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- scp the entire tmp directory if conf.getValue('DEMO-MODE'): report_info('** scp would go here, but cp -r for demonstration purposes') cmd = 'cp -r ' + tmpdir + '* ' + conf.getValue('destdir') run_cmd(cmd, 'using cp to transfer to demo system...') else: scp_target() return def restart_nsd(): if conf.getValue('DEMO-MODE'): cmd = conf.getValue('stop_cmd') run_cmd(cmd, 'stopping nsd...') # BOZO: rebuild is not behaving when there are errors, so the hack is # to remove the existing db, run the zone compiler and restart nsd #cmd = conf.getValue('rebuild_cmd') #os.system(cmd) cmd = 'rm -f ' + conf.getValue('database') run_cmd(cmd, 'removing old zonedb...') cmd = conf.getValue('zonec_cmd') run_cmd(cmd, 'rebuilding zonedb...') cmd = conf.getValue('start_cmd') run_cmd(cmd, 'starting nsd...') else: cmd = 'ssh -a -x ' cmd += conf.getValue('destuser') + '@' + conf.getValue('dest-ip') child = pexpect.spawn(cmd) if not child.isalive(): bail('? cannot login to NSD system at %s' % \ (conf.getValue('dest-ip'))) else: report_info('=> restarting NSD on %s' % \ (conf.getValue('dest-ip'))) child.expect('.*ssword:') child.sendline(conf.getValue('syspw')) child.expect('# ') report_info('=> now logged in') report_info('=> issuing zonec') child.sendline(conf.getValue('zonec_cmd')) if isVerbose(): child.logfile = sys.stdout child.expect('# ') report_info('=> issuing stop') child.sendline(conf.getValue('stop_cmd')) child.expect('# ') report_info('=> issuing start') child.sendline(conf.getValue('start_cmd')) child.expect('# ') child.sendline('exit') child.close() report_info('=> restart done') return def quick_parse(): #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) os.chdir(pwd) return named def run_named_check(named): #-- run named-checkconf on the config file and then run named-checkzone # on each zone file chkconf = conf.getValue('named-checkconf') if os.path.exists(chkconf): fname = conf.getValue('named_root') fname += '/' + conf.getValue('named_conf') report_info('=> running "%s" on "%s"...' % (chkconf, fname)) (output, errors) = run_cmd_capture(chkconf + ' ' + fname) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? wanted to run named-checkconf, dude, but it's not there.") chkzone = conf.getValue('named-checkzone') if os.path.exists(chkzone): zdict = named.getZones() zlist = zdict.keys() zlist.sort() rname = named.getOptions().getDirectory().replace('"','') report_info('=> running "%s" on all zones...' % (chkzone)) prog = re.compile(':[0-9][0-9]*:') for ii in zlist: zone = zdict[ii].getName() zfile = rname + '/' + zdict[ii].getFile() (output, errors) = run_cmd_capture(chkzone + ' ' + zone + ' ' + zfile) if len(output) > 0 and prog.search(output) != None: report_info(output.strip()) else: report_error("? wanted to run named-checkzone, dude, but it's not there.") return def run_zonec(): zonec = conf.getValue('zonec_cmd') if os.path.exists(zonec): report_info('=> running the zone compiler "%s"...' % (zonec)) fname = conf.getValue('nsd_conf') tmpdir = conf.getValue('tmpdir') cmd = zonec + ' -c ' + tmpdir + '/' + fname + ' -d ' + tmpdir cmd += ' -f ' + tmpdir + '/zone.db' os.system('rm -f ' + tmpdir + '/zone.db') (output, errors) = run_cmd_capture(cmd) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? hmph. wanted to run zonec, but it's not there.") return #-- main --------------------------------------------------------------- def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'ahnsv', ['analyze-only', 'help', 'now', 'sync-only', 'verbose'] ) except getopt.GetoptError: usage() sys.exit(1) now = False analyze_only = False sync_only = False for ii, val in opts: if ii in ('-a', '--analyze-only'): analyze_only = True if ii in ('-h', '--help'): usage() sys.exit(0) if ii in ('-n', '--now'): now = True if ii in ('-s', '--sync-only'): sync_only = True if ii in ('-v', '--verbose'): set_verbosity(True) last_stat = {} this_stat = {} #-- don't poll unless we need to... if now: rebuild_nsd_files() cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we just need to sync up to the machine... if sync_only: cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we're just checking things out... if analyze_only: #-- well, and do a couple of extra things, too set_verbosity(True) report_info( \ 'nsd-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version'))) named = quick_parse() rebuild_nsd_files() run_named_check(named) cp_files(analyze_only) run_zonec() sys.exit(0) #-- apparently we need to poll... tmplist = conf.getValue('named_watchlist').split() watchlist = [] for ii in tmplist: watchlist.append(ii.strip()) while True: for ii in watchlist: if ii in last_stat.keys(): statinfo = os.stat(ii) this_stat[ii] = (statinfo.st_size, statinfo.st_mtime) (old_size, old_mtime) = last_stat[ii] (new_size, new_mtime) = this_stat[ii] if old_size != new_size or old_mtime != new_mtime: report_info('aha! "%s" has changed!' % (ii)) last_stat[ii] = (new_size, new_mtime) rebuild_nsd_files() cp_files(analyze_only) restart_nsd() else: statinfo = os.stat(ii) last_stat[ii] = (statinfo.st_size, statinfo.st_mtime) this_stat[ii] = last_stat[ii] time.sleep(int(conf.getValue('sleep_time'))) sys.exit(0) #-- just in case if __name__ == '__main__': main() nsd-4.1.26/contrib/bind2nsd/scripts/s64-sync0000664000175000017500000002652412623035675020213 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # When named.conf changes, update the DNS machine # # #-- imports import getopt import os import os.path import popen2 import re import sys import time if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from Utils import * from NamedConf import * from NsdConf import * else: from bind2nsd.Config import * from bind2nsd.Utils import * from bind2nsd.NamedConf import * from bind2nsd.NsdConf import * if os.path.exists('../pexpect-2.1'): sys.path.append('../pexpect-2.1') import pexpect import pxssh #-- globals conf = Config() #-- useful functions def usage(): print 's64-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: s64-sync [-a|--analyze-only] [-h|--help] [-s|--sync-only]' print ' [-n|--now]' print ' -a | --analyze-only => look for and report errors, but do' print ' not sync with the Secure64 server' print ' -h | --help => print this message and quit' print ' -n | --now => do not poll, sync immediately' print ' -s | --sync-only => sync without translating BIND files' print ' -v | --verbose => output lots of info' return def rebuild_nsd_files(): result = False xlate = conf.getValue('bind2nsd') if os.path.exists(xlate): result = run_cmd(xlate, 'running bind2nsd...') else: report_error('? could not find "%s" and have got to have it' % (xlate)) report_error(' skipping rebuild of NSD files') return result def scp_s64(): #-- do the scp to an actual Secure64 server report_info('=> using scp to transfer to Secure64 system...') tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- this feels a bit dodgy due to issues in pexpect when it goes # up against passwd and other such nastiness from scp/ssh -- all # we should have to do is child.wait() really, but that does not # work as it should. # # NB: it turn out that you can _not_ put a '*' at the end of the # source path; pexpect.spawn() screws up and the parsing of the string # and ends up ignoring everything up to the '*', meaning the command # does not have the 'scp' part in it and does not get executed properly. # pwd = os.getcwd() os.chdir(tmpdir) #-- this is what i wanted to do... #cmd = 'scp -r ' + tmpdir + ' dns@' + conf.getValue('dest-ip') + ':' #-- this is what works... flist = os.listdir('.') fnames = ' '.join(flist) cmd = 'scp -r ' + fnames cmd += ' ' + conf.getValue('destuser') + '@' cmd += conf.getValue('dest-ip') + ':' report_info('=> ' + cmd) child = pexpect.spawn(cmd) if len(conf.getValue('dnspw')) > 0: child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('.*' + conf.getValue('nsd_conf') + '.*') child.expect(pexpect.EOF) child.close() os.chdir(pwd) return def cp_files(analyze): #-- we assume everything has already been copied to the tmpdir by bind2nsd if analyze: return tmpdir = conf.getValue('tmpdir') # must have trailing '/' if not os.path.exists(tmpdir) and not os.path.isdir(tmpdir): bail('? cannot find "%s"...' % (tmpdir)) #-- scp the entire tmp directory if conf.getValue('DEMO-MODE'): report_info('** scp would go here, but cp -r for demonstration purposes') cmd = 'cp -r ' + tmpdir + '* ' + conf.getValue('destdir') run_cmd(cmd, 'using cp to transfer to demo system...') else: scp_s64() return def restart_nsd(): if conf.getValue('DEMO-MODE'): cmd = conf.getValue('stop_cmd') run_cmd(cmd, 'stopping nsd...') # BOZO: rebuild is not behaving when there are errors, so the hack is # to remove the existing db, run the zone compiler and restart nsd #cmd = conf.getValue('rebuild_cmd') #os.system(cmd) cmd = 'rm -f ' + conf.getValue('database') run_cmd(cmd, 'removing old zonedb...') cmd = conf.getValue('zonec_cmd') run_cmd(cmd, 'rebuilding zonedb...') cmd = conf.getValue('start_cmd') run_cmd(cmd, 'starting nsd...') else: cmd = 'ssh -a -x dns@' + conf.getValue('dest-ip') child = pexpect.spawn(cmd) if not child.isalive(): bail('? cannot login to Secure64 system at %s' % \ (conf.getValue('dest-ip'))) else: report_info('=> restarting Secure64 NSD on %s' % \ (conf.getValue('dest-ip'))) child.expect('.*ssword:') child.sendline(conf.getValue('syspw')) child.expect('\[view@.*> ') report_info('=> now logged in') child.sendline('enable dnsconfig') child.expect('.*ssword:') child.sendline(conf.getValue('dnspw')) child.expect('\*.*') report_info('=> issuing zonec') child.sendline('zonec') if isVerbose(): child.logfile = sys.stdout child.expect('\[dnsconfig@.*# ') report_info('=> issuing stop') child.sendline('stop') child.expect('\[dnsconfig@.*# ') report_info('=> issuing start') child.sendline('start') child.expect('\[dnsconfig@.*# ') child.sendline('exit') child.expect('\[view@.*> ') child.sendline('exit') child.close() report_info('=> restart done') return def quick_parse(): #-- build an in-core representation of the named.conf file named_root = conf.getValue('named_root') named_fname = conf.getValue('named_conf') report_info('=> parsing named.conf file \"%s\"...' % (named_fname)) pwd = os.getcwd() if os.path.exists(named_root) and os.path.isdir(named_root): os.chdir(named_root) else: bail('? cannot find the named root directory "%s"' % (named_root)) named = NamedConf(named_fname) os.chdir(pwd) return named def run_named_check(named): #-- run named-checkconf on the config file and then run named-checkzone # on each zone file chkconf = conf.getValue('named-checkconf') if os.path.exists(chkconf): fname = conf.getValue('named_root') fname += '/' + conf.getValue('named_conf') report_info('=> running "%s" on "%s"...' % (chkconf, fname)) (output, errors) = run_cmd_capture(chkconf + ' ' + fname) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? wanted to run named-checkconf, dude, but it's not there.") chkzone = conf.getValue('named-checkzone') if os.path.exists(chkzone): zdict = named.getZones() zlist = zdict.keys() zlist.sort() rname = named.getOptions().getDirectory().replace('"','') report_info('=> running "%s" on all zones...' % (chkzone)) prog = re.compile(':[0-9][0-9]*:') for ii in zlist: zone = zdict[ii].getName() zfile = rname + '/' + zdict[ii].getFile() (output, errors) = run_cmd_capture(chkzone + ' ' + zone + ' ' + zfile) if len(output) > 0 and prog.search(output) != None: report_info(output.strip()) else: report_error("? wanted to run named-checkzone, dude, but it's not there.") return def run_zonec(): zonec = conf.getValue('zonec_cmd') if os.path.exists(zonec): report_info('=> running the zone compiler "%s"...' % (zonec)) fname = conf.getValue('nsd_conf') tmpdir = conf.getValue('tmpdir') cmd = zonec + ' -c ' + tmpdir + '/' + fname + ' -d ' + tmpdir cmd += ' -f ' + tmpdir + '/zone.db' os.system('rm -f ' + tmpdir + '/zone.db') (output, errors) = run_cmd_capture(cmd) if len(errors) > 0: report_info('? errors found --->') report_info(errors) else: report_info(' all is well.') else: report_error("? hmph. wanted to run zonec, but it's not there.") return #-- main --------------------------------------------------------------- def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'ahnsv', ['analyze-only', 'help', 'now', 'sync-only', 'verbose'] ) except getopt.GetoptError: usage() sys.exit(1) now = False analyze_only = False sync_only = False for ii, val in opts: if ii in ('-a', '--analyze-only'): analyze_only = True if ii in ('-h', '--help'): usage() sys.exit(0) if ii in ('-n', '--now'): now = True if ii in ('-s', '--sync-only'): sync_only = True if ii in ('-v', '--verbose'): set_verbosity(True) last_stat = {} this_stat = {} #-- don't poll unless we need to... if now: rebuild_nsd_files() cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we just need to sync up to the Secure64 machine... if sync_only: cp_files(analyze_only) restart_nsd() sys.exit(0) #-- ...and don't poll if we're just checking things out... if analyze_only: #-- well, and do a couple of extra things, too set_verbosity(True) report_info( \ 's64-sync %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version'))) named = quick_parse() rebuild_nsd_files() run_named_check(named) cp_files(analyze_only) run_zonec() sys.exit(0) #-- apparently we need to poll... tmplist = conf.getValue('named_watchlist').split() watchlist = [] for ii in tmplist: watchlist.append(ii.strip()) while True: for ii in watchlist: if ii in last_stat.keys(): statinfo = os.stat(ii) this_stat[ii] = (statinfo.st_size, statinfo.st_mtime) (old_size, old_mtime) = last_stat[ii] (new_size, new_mtime) = this_stat[ii] if old_size != new_size or old_mtime != new_mtime: report_info('aha! "%s" has changed!' % (ii)) last_stat[ii] = (new_size, new_mtime) rebuild_nsd_files() cp_files(analyze_only) restart_nsd() else: statinfo = os.stat(ii) last_stat[ii] = (statinfo.st_size, statinfo.st_mtime) this_stat[ii] = last_stat[ii] time.sleep(int(conf.getValue('sleep_time'))) sys.exit(0) #-- just in case if __name__ == '__main__': main() nsd-4.1.26/contrib/bind2nsd/scripts/s64-mkpw0000664000175000017500000000510010651575270020177 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # encrypt a passwd (very simplistic for now, using GPG or such-like # key someday) # # #-- imports import os import os.path import sys import getpass import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * else: from bind2nsd.Config import * if os.path.exists('../pyDes-1.2'): sys.path.append('../pyDes-1.2') import pyDes #-- globals conf = Config() #-- useful functions def usage(): print 's64-mkpw %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) print print 'usage: s64-mkpw' return def mkprintable(val): cstr = '' for ii in range(0, len(val)): c = val[ii] cstr += '%d ' % (ord(c)) return cstr #-- main --------------------------------------------------------------- def main(): if len(sys.argv) > 1: usage() sys.exit(1) print 's64-mkpw %s, copyright(c) 2007, Secure64 Software Corporation' \ % (conf.getValue('version')) syspw = getpass.getpass('sysconfig password: ') dnspw = getpass.getpass('dnsconfig password: ') fd = open(conf.getValue('password_file'), 'w+') obj = pyDes.triple_des('aBcDeFgHiJkLmNoP', pyDes.ECB) fd.write(mkprintable(obj.encrypt(syspw, '#')) + '\n') fd.write(mkprintable(obj.encrypt(dnspw, '#')) + '\n') fd.close() print '=> stored password in "%s"' % (conf.getValue('password_file')) return if __name__ == '__main__': main() nsd-4.1.26/contrib/bind2nsd/bind2nsd/0000775000175000017500000000000013401455021016667 5ustar wouterwouternsd-4.1.26/contrib/bind2nsd/bind2nsd/Zone.py0000664000175000017500000000637010651575270020177 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a zone file # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class Zone: def __init__(self, name): self.name = name self.file = '' self.type = '' self.masters = [] # empty unless we're a slave zone self.allow_transfer = [] self.also_notify = [] self.allow_notify = [] return def dump(self): report_info('=> Zone:') report_info(' name = %s' % (self.name)) report_info(' file = %s' % (self.file)) report_info(' type = %s' % (self.type)) report_info(' masters = %s' % (str(self.masters))) report_info(' allow_notify = %s' % (str(self.allow_notify))) report_info(' allow_transfer = %s' % (str(self.allow_transfer))) report_info(' also_notify = %s' % (str(self.also_notify))) return def setName(self, name): self.name = name return def getName(self): return self.name def setFile(self, file): self.file = file return def getFile(self): return self.file def setType(self, type): self.type = type return def getType(self): return self.type def addMaster(self, quad): self.masters.append(quad) return def setMasters(self, list): self.masters = list return def getMasters(self): return self.masters def addAllowTransfer(self, quad): self.allow_transfer.append(quad) return def setAllowTransfers(self, list): self.allow_transfer = list return def getAllowTransfer(self): return self.allow_transfer def addAlsoNotify(self, quad): self.also_notify.append(quad) return def setAlsoNotify(self, list): self.also_notify = list return def getAlsoNotify(self): return self.also_notify def addAllowNotify(self, quad): self.allow_notify.append(quad) return def setAllowNotify(self, list): self.allow_notify = list return def getAllowNotify(self): return self.allow_notify nsd-4.1.26/contrib/bind2nsd/bind2nsd/Config.py0000664000175000017500000001247410651575270020473 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # class to represent all of the bind2nsd/syncem config items # import os import os.path import sys if os.path.exists('../pyDes-1.2'): sys.path.append('../pyDes-1.2') import pyDes def mkcipher(val): data = val.split() ctxt = '' for ii in range(0, len(data)): ctxt += chr(int(data[ii])) return ctxt def mkprintable(val): cstr = '' for ii in range(0, len(val)): c = val[ii] cstr += '%d ' % (ord(c)) return cstr class Config: def __init__(self): #-- set all of the defaults self.fname = '' self.config = \ { 'acl_list' : 'acl_list', 'bind2nsd' : '/usr/bin/bind2nsd', 'database' : '"nsd.db"', 'DEBUG' : False, 'DEMO-MODE' : False, 'destdir' : '/tmp/foobar', 'dest-ip' : '127.0.0.1', 'destuser' : 'dns', 'difffile' : '"ixfr.db"', 'dnspw' : 'iforgot', 'identity' : '"unknown"', 'ip-address' : '127.0.0.1', 'logfile' : '"log"', 'named-checkconf' : '/usr/sbin/named-checkconf', 'named-checkzone' : '/usr/sbin/named-checkzone', 'named_root' : '/etc/bind9', 'named_conf' : 'named.conf', 'named_watchlist' : '/etc/named.conf', 'nsd-checkconf' : '/usr/sbin/nsd-checkconf', 'nsd_conf' : 'nsd.conf', 'nsd_conf_dir' : '/etc/nsd/', 'nsd_preamble' : 'nsd.conf-preamble', 'password_file' : '/etc/bind2nsd/passwd', 'pidfile' : '"nsd.pid"', 'port' : '53', 'rebuild_cmd' : '/etc/init.d/nsdc rebuild', 'restart_cmd' : '/etc/init.d/nsdc restart', 'sleep_time' : '5', 'start_cmd' : '/etc/init.d/nsdc start', 'statistics' : '3600', 'stop_cmd' : '/etc/init.d/nsdc stop', 'syspw' : 'iforgot', 'tmpdir' : '/tmp/secure64/', # must have trailing '/' 'username' : 'nsd', 'version' : '0.5.0', 'xfrd-reload-timeout' : '10', 'zonec_cmd' : '/etc/init.d/zonec', } self.init() self.read_passwords() if self.config['DEBUG']: self.dump() return def init(self): fname = '' if os.path.exists('bind2nsd.conf'): self.fname = 'bind2nsd.conf' else: fname = os.getenv('HOME', '.') + '/bind2nsd.conf' if os.path.exists(fname): self.fname = fname else: if os.path.exists('/etc/bind2nsd/bind2nsd.conf'): self.fname = '/etc/bind2nsd/bind2nsd.conf' else: print '? hrm. no config file found -- did you _mean_ that?' #-- override the defaults if self.fname != '': fd = open(self.fname, 'r') line = fd.readline() while line: if len(line) > 0: info = line.split() if line[0] == '#': pass # ignore comments elif len(info) > 0: item = info[0].strip() if info[1].strip() == '=': if item in self.config: self.config[item] = ' '.join(info[2:]) else: pass # ignore lines with only one field else: pass # ignore empty lines line = fd.readline() return def read_passwords(self): fname = self.config['password_file'] if os.path.exists(fname): fd = open(fname, 'r+') syspw = fd.readline() dnspw = fd.readline() fd.close() obj = pyDes.triple_des('aBcDeFgHiJkLmNoP', pyDes.ECB) self.config['syspw'] = obj.decrypt(mkcipher(syspw), '#') self.config['dnspw'] = obj.decrypt(mkcipher(dnspw), '#') return def getValue(self, item): if item in self.config: return self.config[item] else: return None def setValue(self, item, val): if item in self.config: self.config[item] = val else: print '? no such config item "%s" (%s)' % (item, val) return def dump(self): print '=> Config:' print ' %-20s = %s' % ('fname', self.fname) for ii in self.config: print ' %-20s = %s' % (ii, self.config[ii]) return nsd-4.1.26/contrib/bind2nsd/bind2nsd/NsdConf.py0000664000175000017500000003733510651575270020623 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a nsd.conf file # # import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class NsdKey: def __init__(self, name): self.name = name self.algorithm = '' self.secret = '' return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> NsdKey:' print >> ofile,' name = %s' % (self.name) print >> ofile,' algorithm = %s' % (self.algorithm) print >> ofile,' secret = %s' % (self.secret) else: print >> ofile, 'key:' print >> ofile,' name: "%s"' % (self.name) print >> ofile,' algorithm: %s' % (self.algorithm) print >> ofile,' secret: "%s"' % (self.secret) return def setName(self, val): self.name = val return def getName(self): return self.name def setAlgorithm(self, val): self.algorithm = val return def getAlgorithm(self): return self.algorithm def setSecret(self, val): self.secret = val return def getSecret(self): return self.secret class NsdZone: def __init__(self, name, config, ipkeymap): self.name = name self.config = config self.include = '' self.zonefile = '' self.type = '' self.allow_notify = [] # empty unless we're a slave zone self.also_notify = [] # empty unless we're a master zone self.provide_xfr = [] self.oldrootdir = '' self.ipkeymap = ipkeymap return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> NsdZone:' print >> ofile, ' name = %s' % (self.name) print >> ofile, ' include = %s' % (self.include) print >> ofile, ' zonefile = %s' % (self.zonefile) print >> ofile, ' type = %s' % (self.type) print >> ofile, ' allow_notify = %s' % (str(self.allow_notify)) print >> ofile, ' also_notify = %s' % (str(self.also_notify)) print >> ofile, ' provide_xfr = %s' % (str(self.provide_xfr)) else: print >> ofile, '' print >> ofile, 'zone:' print >> ofile, ' name: "%s"' % (self.name) print >> ofile, ' zonefile: "%s"' % (self.zonefile) # BOZO: this is a hack to avoid errors in the zone compiler # and needs to be handled more intelligently; this allows the # zone file to be non-existent (done by some ISPs) but still # listed in the named.conf if not os.path.exists(self.oldrootdir + self.zonefile): report_error('? missing zone file "%s"' % \ (self.oldrootdir + self.zonefile)) nlist = self.allow_notify if self.type == 'slave': print >> ofile, ' # this is a slave zone. masters are listed next.' for ii in nlist: print >> ofile, ' allow-notify: %s NOKEY' % (ii) print >> ofile, ' request-xfr: %s NOKEY' % (ii) else: print >> ofile, ' include: "%s"' % (self.include) for ii in self.also_notify: print >> ofile, ' notify: %s NOKEY' % (ii) for ii in self.provide_xfr: if ii in self.ipkeymap: print >> ofile, ' provide-xfr: %s %s' % (ii, self.ipkeymap[ii]) print >> ofile, ' notify: %s %s' % (ii, self.ipkeymap[ii]) else: print >> ofile, ' provide-xfr: %s NOKEY' % (ii) print >> ofile, ' notify: %s NOKEY' % (ii) return def setName(self, name): self.name = name return def getName(self): return self.name def setOldRootDir(self, name): self.oldrootdir = name return def getOldRootDir(self): return self.oldrootdir def setZonefile(self, file): self.zonefile = file return def getZonefile(self): return self.zonefile def setType(self, type): self.type = type return def getType(self): return self.type def addMaster(self, quad): self.masters.append(quad) return def getMasters(self): return self.masters def setInclude(self, name): self.include = name return def getInclude(self): return self.include def setAllowNotify(self, quad_list): self.allow_notify = quad_list return def getAllowNotify(self): return self.allow_notify def addAllowNotify(self, nlist): self.allow_notify.append(nlist) return def setAlsoNotify(self, quad_list): self.also_notify = quad_list return def getAlsoNotify(self): return self.also_notify def addAlsoNotify(self, nlist): self.also_notify.append(nlist) return def setProvideXfr(self, quad_list): self.provide_xfr = quad_list return def getProvideXfr(self): return self.provide_xfr class NsdOptions: def __init__(self, config): self.database = config.getValue('database') self.difffile = config.getValue('difffile') self.identity = config.getValue('identity') self.ip_address = config.getValue('ip-address') self.logfile = config.getValue('logfile') self.pidfile = config.getValue('pidfile') self.port = config.getValue('port') self.statistics = config.getValue('statistics') self.username = config.getValue('username') self.xfrd_reload_timeout = config.getValue('xfrd-reload-timeout') return def dump(self, ofile): if ofile == sys.stdout: print >> ofile, '=> Options:' print >> ofile, ' database: %s' % (self.database) print >> ofile, ' difffile: %s' % (self.difffile) print >> ofile, ' identity: %s' % (self.identity) print >> ofile, ' ip-address: %s' % (self.ip_address) print >> ofile, ' logfile: %s' % (self.logfile) print >> ofile, ' pidfile: %s' % (self.pidfile) print >> ofile, ' port: %s' % (self.port) print >> ofile, ' statistics: %s' % (self.statistics) print >> ofile, ' username: %s' % (self.username) print >> ofile, ' xfrd-reload-timeout: %s' % (self.xfrd_reload_timeout) else: print >> ofile, '#' print >> ofile, '# All of the values below have been pulled from' print >> ofile, '# either defaults or the config file' print >> ofile, '#' print >> ofile, '' print >> ofile, 'server:' print >> ofile, ' database: %s' % (self.database) print >> ofile, ' difffile: %s' % (self.difffile) print >> ofile, ' identity: %s' % (self.identity) iplist = self.ip_address.split() for ii in iplist: print >> ofile, ' ip-address: %s' % (ii.strip()) print >> ofile, ' logfile: %s' % (self.logfile) print >> ofile, ' pidfile: %s' % (self.pidfile) print >> ofile, ' port: %s' % (self.port) print >> ofile, ' statistics: %s' % (self.statistics) print >> ofile, ' username: %s' % (self.username) print >> ofile, ' xfrd-reload-timeout: %s' % \ (self.xfrd_reload_timeout) print >> ofile, '' return def setDatabase(self, name): self.database = name return def getDatabase(self): return self.database def setDifffile(self, name): self.difffile = name return def getDifffile(self): return self.difffile def setIdentity(self, name): self.identity = name return def getIdentity(self): return self.identity def setIpAddress(self, quad): self.ip_address = quad return def getIpAddress(self): return self.ip_address def setLogfile(self, val): self.logfile = val return def getLogfile(self): return self.logfile def setPort(self, val): self.port = val return def getPort(self): return self.port def setPidfile(self, val): self.pidfile = val return def getPidfile(self): return self.pidfile def setStatistics(self, val): self.statistics = val return def getStatistics(self): return self.statistics def setXfrdReloadTimeout(self, val): self.xfrd_reload_timeout = val return def getXfrdReloadTimeout(self): return self.xfrd_reload_timeout class NsdConf: def __init__(self, config): self.config = config self.fname = config.getValue('nsd_conf') self.files = config.getValue('nsd_files') self.preamble = config.getValue('nsd_preamble') self.acl_list = config.getValue('acl_list') self.oldrootdir = '' self.options = NsdOptions(config) self.includes = [] self.zones = {} self.keys = {} self.ipkeymap = {} return def populate(self, named): self.oldrootdir = named.getOptions().getDirectory().replace('"','') if self.oldrootdir[len(self.oldrootdir)-1] != '/': self.oldrootdir += '/' klist = named.getKeys() for ii in klist: oldk = named.getKey(ii) k = NsdKey(oldk.getName()) k.setAlgorithm(oldk.getAlgorithm()) k.setSecret(oldk.getSecret()) self.keys[k.getName()] = k #-- map each of the key ip addresses for faster lookup on dump() iplist = oldk.getIpAddrs() for jj in iplist: if jj not in self.ipkeymap: self.ipkeymap[jj] = k.getName() zlist = named.getZones() for ii in zlist: oldz = named.getZone(ii) z = NsdZone(oldz.getName(), self.config, self.ipkeymap) z.setZonefile(oldz.getFile()) z.setInclude(self.acl_list) z.setOldRootDir(self.oldrootdir) if 'slave' in oldz.getType().split(): z.setType('slave') # not used, but nice to know nlist = oldz.getMasters() for ii in nlist: z.addAllowNotify(ii) if len(oldz.getAllowNotify()) > 0: nlist = oldz.getAllowNotify() else: nlist = named.getOptions().getAllowNotify() for ii in nlist: z.addAllowNotify(ii) else: z.setType('master') if len(oldz.getAlsoNotify()): nlist = oldz.getAlsoNotify() else: nlist = named.getOptions().getAlsoNotify() for ii in nlist: z.addAlsoNotify(ii) if len(named.getOptions().getAllowTransfer()) > 0: z.setProvideXfr(named.getOptions().getAllowTransfer()) self.zones[z.getName()] = z return def dump(self): report_info('=> NsdConf: dumping data from \"%s\"...' % (self.fname)) self.options.dump(sys.stdout) report_info('=> NsdConf: list of includes...') report_info( str(self.includes)) report_info('=> NsdConf: zone info...') zlist = self.zones.keys() zlist.sort() for ii in zlist: self.zones[ii].dump(sys.stdout) report_info('=> NsdConf: key info...') klist = self.keys.keys() klist.sort() for ii in klist(): self.keys[ii].dump(sys.stdout) return def write_conf(self): nfile = open(self.fname, 'w+') self.options.dump(nfile) klist = self.keys.keys() klist.sort() for ii in klist: self.keys[ii].dump(nfile) zlist = self.zones.keys() zlist.sort() for ii in zlist: report_info(' writing info for zone "%s"...' % (self.zones[ii].getName())) self.zones[ii].dump(nfile) nfile.close() return def do_generate(self, newfd, start, stop, step, lhs, rrtype, rhs): #-- write the equivalent of the $GENERATE for ii in range(start, stop, step): left = lhs.replace('$', str(ii)) right = rhs.replace('$', str(ii)) print >> newfd, '%s %s %s' % (left, rrtype, right) return def make_zone_copy(self, oldpath, newpath): #-- copy the zone file line-by-line so we can catch $GENERATE usage report_info('=> copying "%s" to "%s"' % (oldpath, newpath)) if not os.path.exists(oldpath): os.system('touch ' + newpath) return oldfd = open(oldpath, 'r+') newfd = open(newpath, 'w+') line = oldfd.readline() while line: fields = line.split() if len(fields) > 0 and fields[0].strip() == '$GENERATE': report_info('=> processing "%s"...' % (line.strip())) index = 1 #-- determine start/stop range indices = fields[index].split('-') start = 0 stop = 0 if len(indices) == 2: start = int(indices[0]) stop = int(indices[1]) if stop < start: bail('? stop < start in range "%s"' % (fields[1].strip())) else: bail('? invalid range "%s"' % (fields[1].strip())) index += 1 #-- determine increment step = 1 if len(fields) == 6: step = int(fields[index]) index += 1 #-- get lhs lhs = fields[index].strip() index += 1 #-- get RR type rrtype = fields[index].strip() if rrtype not in [ 'NS', 'PTR', 'A', 'AAAA', 'DNAME', 'CNAME' ]: bail('? illegal RR type "%s"' % (rrtype)) index += 1 #-- get rhs rhs = fields[index].strip() index += 1 #-- do the $GENERATE self.do_generate(newfd, start, stop, step, lhs, rrtype, rhs) else: #-- just copy the line as is print >> newfd, line, line = oldfd.readline() oldfd.close() newfd.close() return def write_zone_files(self): acls = {} zlist = self.zones.keys() zlist.sort() for ii in zlist: oldpath = self.oldrootdir + self.zones[ii].getZonefile() newpath = self.config.getValue('tmpdir') + self.zones[ii].getZonefile() if not os.path.exists(os.path.dirname(newpath)): os.makedirs(os.path.dirname(newpath)) self.make_zone_copy(oldpath, newpath) incl = self.zones[ii].getInclude() if acls.has_key(incl): acls[incl] += 1 else: acls[incl] = 1 alist = acls.keys() alist.sort() for ii in alist: newpath = self.config.getValue('tmpdir') + ii run_cmd('touch ' + newpath, 'touch "%s"' % (newpath)) return def addZone(self, zone): name = zone.getName() self.zones[name] = zone return def getZones(self): return self.zones def addKey(self, key): self.keys[key.getName()] = key return def getKeys(self): return self.keys def getKey(self, name): if name in self.keys: return self.keys[name] else: return None nsd-4.1.26/contrib/bind2nsd/bind2nsd/Parser.py0000664000175000017500000003650510651575270020523 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class containing the parser for BIND configuration files # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from NamedConf import * from Zone import * from Key import * from Tokenizer import * from Utils import * else: from bind2nsd.NamedConf import * from bind2nsd.Zone import * from bind2nsd.Key import * from bind2nsd.Tokenizer import * from bind2nsd.Utils import * #-- the following options {} clauses are currently currently ignored, # typically because they are not implemented or not applicable to NSD IGNORED_OPTIONS = [ 'cleaning-interval', 'datasize', 'interface-interval', 'max-cache-size', 'stacksize', ] class Parser: def __init__(self, named): self.named = named return def handle_include(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_STRING: fname = val.replace('"', '') self.named.includes.append(fname) report_info(' include file "%s"...' % (fname)) if os.path.exists(fname): self.parse(Tokenizer(fname)) else: report_error('? missing include file "%s"' % (fname)) else: bail('? dude. where is the filename string after "include"?') (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "include" (%d: %s)' % (ttype, val)) return def handle_key(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_STRING: name = val.replace('"', '') key = Key(name) (ttype, val, curline) = tokens.get() if ttype != T_LBRACE: bail('? need opening brace for "key" defn (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() while ttype != T_RBRACE: if ttype == T_KEYWORD and val == 'algorithm': (ttype, val, curline) = tokens.get() if ttype == T_KEYWORD or ttype == T_NAME: key.setAlgorithm(val) else: bail('? bogosity after "algorithm" (%d: %s)' % (ttype, val)) elif ttype == T_KEYWORD and val == 'secret': (ttype, val, curline) = tokens.get() if ttype == T_STRING: s = val.replace('"','') key.setSecret(s) else: bail('? bogosity after "secret" (%d: %s)' % (ttype, val)) elif ttype == T_SEMI: pass (ttype, val, curline) = tokens.get() else: bail('? need to have a string after "key" (%d: %s)' % (ttype, val)) self.named.addKey(key) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "key" (%d: %s)' % (ttype, val)) return def handle_server(self, tokens): (ttype, val, curline) = tokens.get() if ttype == T_QUAD: ipaddr = val (ttype, val, curline) = tokens.get() if ttype != T_LBRACE: bail('? need opening brace for "server" (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() while ttype != T_RBRACE: if ttype == T_KEYWORD and val == 'keys': (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: nlist = self.name_list(val, tokens) for ii in nlist: self.named.keys[ii].addIpAddr(ipaddr) else: bail('? bogosity after "keys" (%d: %s)' % (ttype, val)) (ttype, val, curline) = tokens.get() else: bail('? need to have an IP address after "server" (%d: %s)' % \ (ttype, val)) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "server" (%d: %s)' % (ttype, val)) return def name_list(self, name, tokens): nlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_NAME: nlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass else: bail('? was expecting a name in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return nlist def quad_list(self, name, tokens): qlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_QUAD: qlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass else: bail('? was expecting a quad in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return qlist def quad_list_with_keys(self, name, tokens, named): qlist = [] (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_QUAD: qlist.append(val) elif ttype == T_SEMI or ttype == T_COMMENT: pass elif ttype == T_KEYWORD and val == 'key': (ttype, val, curline) = tokens.get() if ttype == T_NAME: if val in named.getKeys(): qlist.append(val) else: bail('? was expecting a key name in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) else: bail('? was expecting a quad in "%s" (%d, %d: %s)' % \ (name, ttype, curline, val.strip())) (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? junk after closing brace of "%s" section' % (name)) return qlist def skip_value(self, name, tokens): (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_STRING: pass else: bail('? need something after "%s" keyword (%d: %s)' % (name, ttype, val)) return def handle_options(self, tokens): report_info('=> processing server options') optsDone = False depth = 0 (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: depth += 1 else: bail('? urk. bad info after "options" keyword.') (ttype, val, curline) = tokens.get() while not optsDone: if ttype == T_KEYWORD and val == 'directory': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setDirectory(val) else: bail('? need string after "directory" keyword') elif ttype == T_KEYWORD and val == 'dump-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setDumpFile(val) else: bail('? need string after "dump-file" keyword') elif ttype == T_KEYWORD and val == 'pid-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setPidFile(val) else: bail('? need string after "pid-file" keyword') elif ttype == T_KEYWORD and val == 'coresize': (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_KEYWORD: self.named.options.setCoresize(val) else: bail('? need name after "coresize" keyword (%d: %s)' % \ (ttype, val)) elif ttype == T_KEYWORD and val == 'version': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setVersion(val) else: bail('? need string after "version" keyword') elif ttype == T_KEYWORD and val == 'transfer-format': (ttype, val, curline) = tokens.get() if ttype == T_NAME or ttype == T_KEYWORD: self.named.options.setTransferFormat(val) else: bail('? need name after "transfer-format" keyword (%d: %s)' % \ (ttype, val)) elif ttype == T_KEYWORD and val == 'statistics-file': (ttype, val, curline) = tokens.get() if ttype == T_STRING: self.named.options.setStatisticsFile(val) else: bail('? need string after "statistics-file" keyword') elif ttype == T_KEYWORD and val == 'allow-transfer': qlist = self.quad_list_with_keys(val, tokens, self.named) self.named.options.setAllowTransfer(qlist) elif ttype == T_KEYWORD and val == 'allow-notify': qlist = self.quad_list(val, tokens) self.named.options.setAllowNotify(qlist) elif ttype == T_KEYWORD and val == 'also-notify': qlist = self.quad_list(val, tokens) self.named.options.setAlsoNotify(qlist) elif ttype == T_KEYWORD and val == 'allow-recursion': qlist = self.quad_list(val, tokens) self.named.options.setAllowRecursion(qlist) elif ttype == T_KEYWORD and val == 'check-names': (ttype, val, curline) = tokens.get() info = [] while ttype != T_SEMI: info.append(val) (ttype, val, curline) = tokens.get() self.named.options.addCheckNames(' '.join(info)) elif ttype == T_KEYWORD and val in IGNORED_OPTIONS: self.skip_value(val, tokens) elif ttype == T_KEYWORD and val == 'recursive-clients': (ttype, val, curline) = tokens.get() if ttype == T_QUAD: # well, it's a number, actually... self.named.options.setRecursiveClients(val) else: bail('? need value after "recursive-clients" keyword (%d: %s)' % (ttype, val)) elif ttype == T_RBRACE: optDone = True break (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? um, junk after closing brace of "options" section') return def handle_zone(self, tokens): (ttype, val, curline) = tokens.get() if ttype != T_STRING: bail('? expected string for zone name (%d: %s)' % (ttype, val)) zname = val.replace('"','') zone = Zone(zname) (ttype, val, curline) = tokens.get() if ttype == T_KEYWORD and (val == 'in' or val == 'IN'): (ttype, val, curline) = tokens.get() if ttype == T_LBRACE or ttype == T_LPAREN: (ttype, val, curline) = tokens.get() while ttype != T_RBRACE and ttype != T_RPAREN: if ttype == T_KEYWORD and val == 'type': (ttype, val, curline) = tokens.get() info = [] while ttype == T_KEYWORD or ttype == T_NAME: info.append(val) (ttype, val, curline) = tokens.get() zone.setType(' '.join(info)) elif ttype == T_KEYWORD and val == 'file': (ttype, val, curline) = tokens.get() if ttype != T_STRING: bail('? eh? no string for zone file name? (%d: %s)' % \ (ttype, val)) fname = val.replace('"','') zone.setFile(fname) elif ttype == T_KEYWORD and val == 'masters': qlist = self.quad_list(val, tokens) zone.setMasters(qlist) elif ttype == T_KEYWORD and val == 'allow-transfer': qlist = self.quad_list_with_keys(val, tokens, self.named) zone.setAllowTransfers(qlist) elif ttype == T_KEYWORD and val == 'also-notify': qlist = self.quad_list(val, tokens) zone.setAlsoNotify(qlist) elif ttype == T_SEMI: pass else: bail('? bugger. do NOT grok "%s" yet (%d: %s @ line %s)' % \ (val, ttype, val, curline)) (ttype, val, curline) = tokens.get() self.named.addZone(zone) else: bail('? expected left brace to start zone definition (%d: %s)' % \ (ttype, val)) (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? need a semicolon to end the "zone" (%d: %s)' % (ttype, val)) return def ignore_section(self, name, tokens): report_info('=> ignoring %s' % (name)) done = False depth = 0 (ttype, val, curline) = tokens.get() if ttype == T_LBRACE: depth += 1 else: bail('? urk. bad info after "%s" keyword.' % (name)) (ttype, val, curline) = tokens.get() while not done: if ttype == T_LBRACE: depth += 1 elif ttype == T_RBRACE: depth -= 1 if depth == 0: break else: pass (ttype, val, curline) = tokens.get() (ttype, val, curline) = tokens.get() if ttype != T_SEMI: bail('? um, junk after closing brace of "%s" section' % (name)) return def parse(self, tokens): (ttype, val, curline) = tokens.get() while ttype != T_EOF: if ttype == T_COMMENT: pass elif ttype == T_KEYWORD and val == 'controls': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'key': self.handle_key(tokens) elif ttype == T_KEYWORD and val == 'include': self.handle_include(tokens) elif ttype == T_KEYWORD and val == 'logging': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'lwres': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'options': self.handle_options(tokens) elif ttype == T_KEYWORD and val == 'server': self.handle_server(tokens) elif ttype == T_KEYWORD and val == 'trusted-keys': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'view': self.ignore_section(val, tokens) elif ttype == T_KEYWORD and val == 'zone': self.handle_zone(tokens) else: bail('? ew. what _is_ this? -> %2d: %s @ line %d' \ % (ttype, val, curline)) (ttype, val, curline) = tokens.get() return nsd-4.1.26/contrib/bind2nsd/bind2nsd/Key.py0000664000175000017500000000443110651575270020010 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a named.conf key # # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Utils import * else: from bind2nsd.Utils import * class Key: def __init__(self, name): self.name = name self.algorithm = '' self.secret = '' self.ipaddrs = [] return def dump(self): report_info('=> Key:') report_info(' algorithm = %s' % (self.algorithm)) report_info(' name = %s' % (self.name)) report_info(' secret = %s' % (self.secret)) report_info(' ipaddrs = %s' % (str(self.ipaddrs))) return def setName(self, val): self.name = val return def getName(self): return self.name def setAlgorithm(self, val): self.algorithm = val return def getAlgorithm(self): return self.algorithm def setSecret(self, val): self.secret = val return def getSecret(self): return self.secret def addIpAddr(self, addr): if addr not in self.ipaddrs: self.ipaddrs.append(addr) return def getIpAddrs(self): return self.ipaddrs nsd-4.1.26/contrib/bind2nsd/bind2nsd/Utils.py0000664000175000017500000000465110647326614020365 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # utility functions used throughout the package # # import popen2 import sys VERBOSE = False def set_verbosity(flag): global VERBOSE VERBOSE = flag return def isVerbose(): global VERBOSE return VERBOSE def report_error(somestuff): if len(somestuff) > 0: print >> sys.stderr, somestuff sys.stderr.flush() return def report_info(somestuff): global VERBOSE if VERBOSE and len(somestuff) > 0: print >> sys.stdout, somestuff sys.stdout.flush() return def bail(somestuff): report_error(somestuff) sys.exit(1) return def run_cmd_capture(cmd): (cout, cin, cerr) = popen2.popen3(cmd) cin.close() output = cout.readlines() cout.close() errors = cerr.readlines() cerr.close() return (''.join(output), ''.join(errors)) def run_cmd(cmd, desc): #-- run a command using our own particular idiom global VERBOSE result = True # T => ran without error reports, F otherwise if VERBOSE and len(desc) > 0: report_info('=> ' + desc) (cout, cin, cerr) = popen2.popen3(cmd) cin.close() output = cout.readlines() cout.close() if VERBOSE: report_info(''.join(output)) errors = cerr.readlines() cerr.close() if len(errors) > 0: result = False report_error(''.join(errors)) return result nsd-4.1.26/contrib/bind2nsd/bind2nsd/__init__.py0000664000175000017500000000217110647326614021017 0ustar wouterwouter# Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # initialize the module # nsd-4.1.26/contrib/bind2nsd/bind2nsd/Tokenizer.py0000664000175000017500000001127210647326614021234 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to tokenize a named.conf file # # T_KEYWORD = 0 T_STRING = 1 T_LBRACE = 2 T_RBRACE = 3 T_SEMI = 4 T_COMMA = 5 T_QUAD = 6 T_COMMENT = 7 T_NAME = 8 T_EOF = 9 T_LPAREN = 10 T_RPAREN = 11 NAMED_KEYWORDS = [ 'algorithm', 'allow-notify', 'allow-recursion', 'allow-transfer', 'also-notify', 'category', 'channel', 'check-names', 'controls', 'coresize', 'directory', 'dump-file', 'file', 'IN', 'in', 'include', 'key', 'keys', 'logging', 'masters', 'options', 'pid-file', 'print-time', 'recursive-clients', 'secret', 'severity', 'statistics-file', 'syslog', 'transfer-format', 'type', 'version', 'versions', 'zone', ] class Tokenizer: def __init__(self, fname): infile = file(fname) self.data = ''.join(infile.readlines()) self.curpos = 0 self.lastpos = len(self.data) self.line = 1 return def get(self): tok = '' done = False while not done: if self.curpos >= self.lastpos: return (T_EOF, None, self.line) c = self.data[self.curpos] if c == '\n': self.line += 1 if c.isspace(): self.curpos += 1 continue elif c == '{': self.curpos += 1 return (T_LBRACE, c, self.line) elif c == '}': self.curpos += 1 return (T_RBRACE, c, self.line) elif c == '(': self.curpos += 1 return (T_LPAREN, c, self.line) elif c == ')': self.curpos += 1 return (T_RPAREN, c, self.line) elif c == ';': self.curpos += 1 return (T_SEMI, c, self.line) elif c == '#': while c != '\n': tok += c self.curpos += 1 c = self.data[self.curpos] self.curpos += 1 if c == '\n': self.line += 1 return (T_COMMENT, tok, self.line) elif c == '"': tok += c self.curpos += 1 c = self.data[self.curpos] while c != '"': tok += c self.curpos += 1 c = self.data[self.curpos] tok += c self.curpos += 1 return (T_STRING, tok, self.line) elif c == '/' and self.data[self.curpos+1] == '/': while c != '\n': tok += c self.curpos += 1 c = self.data[self.curpos] if c == '\n': self.line += 1 self.curpos += 1 return (T_COMMENT, tok, self.line) elif c == '/' and self.data[self.curpos+1] == '*': cmtDone = False tok += c tok += self.data[self.curpos+1] self.curpos += 2 c = self.data[self.curpos] while not cmtDone: if c == '*' and self.data[self.curpos+1] == '/': tok += c tok += self.data[self.curpos+1] self.curpos += 2 return (T_COMMENT, tok, self.line) else: tok += c if c == '\n': self.line += 1 self.curpos +=1 c = self.data[self.curpos] return (T_COMMENT, tok, self.line) elif c.isdigit(): tok += c self.curpos += 1 c = self.data[self.curpos] while c.isdigit() or c == '.' or c == '/': tok += c self.curpos += 1 c = self.data[self.curpos] return (T_QUAD, tok, self.line) else: while c.isalnum() or c == '_' or c == '-' or c == '.': tok += c self.curpos += 1 c = self.data[self.curpos] if tok in NAMED_KEYWORDS: return (T_KEYWORD, tok, self.line) else: return (T_NAME, tok, self.line) return def dump(self): print 'Tokenizer raw data:' print 'cur, last: %d, %d' % (self.curpos, self.lastpos) print self.data return nsd-4.1.26/contrib/bind2nsd/bind2nsd/NamedConf.py0000664000175000017500000001446410651575270021121 0ustar wouterwouter#!/usr/bin/env python # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # class to represent a named.conf file # import os import os.path import sys if os.path.exists('../bind2nsd/Config.py'): sys.path.append('../bind2nsd') from Config import * from Parser import * from Zone import * from Utils import * else: from bind2nsd.Config import * from bind2nsd.Parser import * from bind2nsd.Zone import * from bind2nsd.Utils import * class Options: def __init__(self): self.allow_notify = [] self.allow_recursion = [] self.allow_transfer = [] self.also_notify = [] self.check_names = [] self.coresize = "" self.directory = "" self.dump_file = "" self.pid_file = "" self.recursive_clients = "" self.statistics_file = "" self.transfer_format = "" self.version = "" return def dump(self): report_info('=> Options:') report_info(' allow-notify: %s' % (self.allow_notify)) report_info(' allow-recursion: %s' % (self.allow_recursion)) report_info(' allow-transfer: %s' % (self.allow_transfer)) report_info(' also-notify: %s' % (self.also_notify)) report_info(' check-names: %s' % (str(self.check_names))) report_info(' coresize: %s' % (self.coresize)) report_info(' directory: %s' % (self.directory)) report_info(' dump-file: %s' % (self.dump_file)) report_info(' pid-file: %s' % (self.pid_file)) report_info(' recursive-clients: %s' % (self.recursive_clients)) report_info(' statistics-file: %s' % (self.statistics_file)) report_info(' transfer-format: %s' % (self.transfer_format)) report_info(' version: %s' % (self.version)) return def setDirectory(self, name): self.directory = name return def getDirectory(self): return self.directory def setDumpFile(self, name): self.dump_file = name return def getDumpFile(self): return self.dump_file def setPidFile(self, name): self.pid_file = name return def getPidFile(self): return self.pid_file def setStatisticsFile(self, name): self.statistics_file = name return def getStatisticsFile(self): return self.statistics_file def addAllowNotify(self, quad): self.allow_notify.append(quad) return def setAllowNotify(self, list): self.allow_notify = list return def getAllowNotify(self): return self.allow_notify def addAllowTransfer(self, quad): self.allow_transfer.append(quad) return def setAllowTransfer(self, list): self.allow_transfer = list return def getAllowTransfer(self): return self.allow_transfer def addAlsoNotify(self, quad): self.also_notify.append(quad) return def setAlsoNotify(self, list): self.also_notify = list return def getAlsoNotify(self): return self.also_notify def addAllowRecursion(self, quad): self.allow_recursion.append(quad) return def setAllowRecursion(self, list): self.allow_recursion = list return def getAllowRecursion(self): return self.allow_recursion def addCheckNames(self, val): self.check_names.append(val) return def getCheckNames(self): return self.check_names def setCoresize(self, val): self.coresize = val return def getCoresize(self): return self.coresize def setTransferFormat(self, val): self.transfer_format = val return def getTransferFormat(self): return self.transfer_format def setVersion(self, val): self.version = val return def getVersion(self): return self.version def setRecursiveClients(self, val): self.recursive_clients = val return def getRecursiveClients(self): return self.recursive_clients class NamedConf: def __init__(self, fname): self.fname = fname self.options = Options() self.includes = [] self.zones = {} self.keys = {} parser = Parser(self) parser.parse(Tokenizer(self.fname)) return def dump(self): report_info('=> NamedConf: dumping data from \"%s\"...' % (self.fname)) self.options.dump() report_info('=> NamedConf: list of includes...') report_info(str(self.includes)) report_info('=> NamedConf: zone info...') zlist = self.zones.keys() zlist.sort() for ii in zlist: self.zones[ii].dump() report_info('=> NamedConf: key info...') klist = self.keys.keys() klist.sort() for ii in klist: self.keys[ii].dump() return def getOptions(self): return self.options def addZone(self, zone): name = zone.getName() self.zones[name] = zone return def getZones(self): return self.zones def getZone(self, name): if name in self.zones: return self.zones[name] else: return None def addKey(self, key): name = key.getName() self.keys[name] = key return def getKey(self, name): if name in self.keys: return self.keys[name] else: return None def getKeys(self): return self.keys nsd-4.1.26/contrib/bind2nsd/COPYING0000664000175000017500000000206310647326614016236 0ustar wouterwouterCopyright (c) 2007, Secure64 Software Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nsd-4.1.26/contrib/bind2nsd/etc/0000775000175000017500000000000013401455021015737 5ustar wouterwouternsd-4.1.26/contrib/bind2nsd/etc/bind2nsd.conf0000664000175000017500000000653410647326614020337 0ustar wouterwouter# Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # config file for bind2nsd # #--- parameters for the bind2nsd command --------------------------------- # default: named_root = /etc/bind9 # default: named_conf = named.conf # default: nsd_conf = nsd.conf # default: nsd_conf_dir = /etc/nsd/ # default: nsd_preamble = nsd.conf-preamble #--- options to fill in the blanks in nsd.conf --------------------------- # default: acl_list = "acl_list" # default: database = "nsd.db" => server data base name # default: difffile = "ixfr.db" => change data base on server # default: identity = "unknown" => nodename for server # default: ip-address = 127.0.0.1 1.2.3.4 => listen for requests on these # default: logfile = "log" => nsd log file on server # default: pidfile = "pid" => nsd pid file on server # default: port = 53 # default: statistics = 3600 # default: username = nsd # default: xfrd-reload-timeout = 10 #-- parameters for s64-sync or s64-mkpw ----------------------------------- # default: bind2nsd = /usr/bin/bind2nsd => where the translation script lives # default: dest-ip = 127.0.0.1 => where to copy to # default: destuser = dns => login name for scp (on server) # default: dnspw = iforgot => dnsconfig password (see s64-mkpw) # default: named-checkconf = /usr/sbin/named-checkconf => BIND command location # default: named-checkzone = /usr/sbin/named-checkzone => BIND command location # default: named_root = /etc/bind9 => default BIND config directory # default: named_conf = named.conf => BIND config file name # default: named_watchlist = /etc/named.conf => config files to poll # default: password_file = /etc/bind2nsd/passwd => encrypted passwords # default: sleep_time = 5 => poll time, in seconds # default: syspw = iforgot => sysconfig password (see s64-mkpw) # default: tmpdir = /tmp/secure64/ => must have trailing slash, is where the # xlated files are stashed #-- only useful in DEMO-MODE in s64-sync # default: destdir = /tmp/foobar => where to copy xlated files to # default: rebuild_cmd = /etc/init.d/nsdc rebuild => rebuild zonedb # default: restart_cmd = /etc/init.d/nsdc restart => restart nsd # default: start_cmd = /etc/init.d/nsdc start => start nsd # default: stop_cmd = /etc/init.d/nsdc stop => stop nsd # default: zonec_cmd = /etc/init.d/zonec => invoke nsd zone compiler nsd-4.1.26/contrib/bind2nsd/MANIFEST0000664000175000017500000000036110647326614016333 0ustar wouterwouterREADME setup.py bind2nsd/Config.py bind2nsd/Key.py bind2nsd/NamedConf.py bind2nsd/NsdConf.py bind2nsd/Parser.py bind2nsd/Tokenizer.py bind2nsd/Utils.py bind2nsd/Zone.py bind2nsd/__init__.py scripts/bind2nsd scripts/s64-mkpw scripts/s64-sync nsd-4.1.26/contrib/bind2nsd/install.sh0000664000175000017500000000235410647646703017214 0ustar wouterwouter#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # install script # python setup.py install (cd pexpect-2.1; python setup.py install) (cd pyDes-1.2; python setup.py install) nsd-4.1.26/contrib/bind2nsd/TODO0000664000175000017500000000410710647646703015700 0ustar wouterwouterto be done: =========== -- key {}'s have to be handled -- zone allow-transfer xlates to what in NSD? -- install process needs cleanup -- document install/update process -- performance: can this be improved? translation ought to be able to go quicker, perhaps by only handling changes vs complete re-translation every time -- license under MIT license and post to newly created bind2nsd.sf.net -- must handle 'control { ... }' settings? -- look for all 'BOZO's -- look for all 'FIXME's -- return code checking is abysmal, if done at all -- trap ctrl-C properly -- verify BIND named.conf grammar details -- verify NSD nsd.conf grammar details -- report specifically what line of what file has an error for ALL errors recently done: ============== -- can now report specifically what line of what file has an error and using it in some interesting places -- refactored the parser (much more maintainable now) -- acl_list: now set these up (as empty files) and copy them to the right places -- if scp does not require a password, and it is set to '' in the config file, then do not wait for the password prompt -- can now specify multiple ip-addresses for use in nsd.conf (and to say which one to scp to when sync'ing using 'dest-ip' option) -- zonec output again displayed when using 's64-sync --verbose' -- search for bind2nsd.conf in '.', $HOME, _and_ /etc/bind2nsd -- install config files, etc., in /etc/bind2nsd (passwd file, too) -- clean up example bind2nsd.conf -- set better config defaults -- GENERATE commands in the zone data are now intercepted and converted to the desired text (since we don't handle $GENERATE and it _is_ a BIND specific tool). -- Added in key xlation (i.e., 'key { ... }') -- 'options { pid-file } => server: pidfile' is ignorable -- handle options { recursive-clients nnn; } -- do not scp when using 's64-sync --analyze-only' -- handle allow-notify {} -- handle also-notify {} in options {} and in server {} or per zone -- create an 'nsd-sync' that works with any old NSD server on a remote machine (permutation of 's64-sync') nsd-4.1.26/contrib/bind2nsd/set_version0000664000175000017500000000432510647326614017471 0ustar wouterwouter#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # set the version number in the right files # if [ $# -ne "1" ] then echo "usage: set_version " exit 1 fi NEWV=$1 #-- report on the current version numbers SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py is currently => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py is currently => ${CONFIGV}" #-- replace them sed --in-place=.bak \ "s/ version = '${SETUPV}',/ version = '${NEWV}',/" setup.py sed --in-place=.bak \ "s/[ \t]*'version'[ \t]*: '${CONFIGV}',/ 'version' : '${NEWV}',/" bind2nsd/Config.py #-- report on the new version numbers SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py is now => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py is now => ${CONFIGV}" nsd-4.1.26/contrib/bind2nsd/README0000664000175000017500000000312010651575270016055 0ustar wouterwouterbind2nsd -- translate from BIND named.conf to NSD nsd.conf -- then, sync up configuration files with a Secure64 server To install these tools on Linux systems: # ./install.sh Then, copy bind2nsd.conf to the directory you will run these commands from (e.g., /etc/named or /etc/bind9) and then edit the values properly. Passwords for logging into a Secure64 system can be stored in the bind2nsd.conf file (as clear text only) or can be stored encrypted by using the 'password_file' config item and the s64-mkpw utility. -- Copyright (c) 2007, Secure64 Software Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nsd-4.1.26/contrib/bind2nsd/setup.py0000664000175000017500000000343410651575270016717 0ustar wouterwouter# # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # installation/setup script for bind2nsd # from distutils.core import setup setup(name = 'bind2nsd', version = '0.5.0', author = 'Secure64 Software Corporation', author_email = 'support@secure64.com', maintainer = 'Al Stone', maintainer_email = 'ahs3@secure64.com', url = 'http://www.secure64.com', description = 'automatic named/nsd translation and synchronization', packages = [ 'bind2nsd' ], scripts = [ 'scripts/bind2nsd', 'scripts/s64-sync', 'scripts/s64-mkpw', ], data_files = [ ('/usr/share/doc/bind2nsd', ['./README', './TODO']), ('/etc/bind2nsd', ['etc/bind2nsd.conf']), ] ) nsd-4.1.26/contrib/bind2nsd/ChangeLog0000664000175000017500000000500212623035675016751 0ustar wouterwouter2007-07-24 Al Stone * bind2nsd/*, scripts/*: cleaned up the way modules were being imported so that it's much simpler, hopefully more reliable. * bind2nsd/Parser.py: added code to recognize but skip the view{}, trusted-keys{}, and lwres{} clauses; added quad_list_with_keys(). * bind2nsd/Zone.py: store allow-notify statements. 2007-07-18 Al Stone * bind2nsd/Config.py: do not open config file with r+ * bind2nsd/NamedConf.py: remove recursive module import when running in ways I hadn't tried. 2007-07-13 Al Stone * etc/: added in some files forgotten when conversion to FOSS.... * scripts/nsd-sync: ...including this one. 2007-07-06 Al Stone * TODO: update. * bind2nsd/Key.py: correct missing ')'. * bind2nsd/Tokenizer.py: reformatting. * bind2nsd/Parser.py: handle 'recursive-clients' option; handle 'allow-notify' option; handle 'also-notify' option in zones. * bind2nsd/NamedConf.py: handle 'allow-notify' option; handle 'also-notify' for simple cases. * bind2nsd/NsdConf.py: handle 'allow-notify' option; handle 'also-notify' for simple cases. 2007-06-29 Al Stone * TODO: update. * bind2nsd/NsdConf.py: when writing zone data files, look for any use of the $GENERATE directive and replace it with the proper RRs; populate info from 'key {}' in BIND. * bind2nsd/Parser.py: add in several 'options {}' clauses that we'll recognize but do nothing about for now; handle multiple 'key {}' clauses; recognize 'server {}' clauses. * bind2nsd/Key.py: add getName(); added self.ipaddrs and methods. * bind2nsd/NamedConf.py: allow for more than one 'key {}' clause. * bind2nsd/Tokenizer.py: added 'keys' as a keyword. 2007-06-28 Al Stone * TODO: update. * bind2nsd/Config.py: 'dest-ip' added as the place to scp files to; search for bind2nsd.conf in '.', $HOME, _and_ /etc/bind2nsd; the default for 'password' file is '/etc/bind2nsd/passwd' _not_ '/etc/secure64/passwd'. * bind2nsd/NsdConf.py: handle multiple 'ip-address' clauses in the 'server' section. * etc/bind2nsd.conf: add 'dest-ip'; add info on all options. * scripts/s64-sync: replace 'ip-address' with 'dest-ip'; make sure zonec output shows up when in verbose mode. * bind2nsd/Utils.py: added isVerbose(). 2007-06-27 Al Stone * TODO: update. * s64-sync: allow for scp to destination when no password needed; clean up demo-mode 'cp -r'. * Config.py: add 'destuser' option. nsd-4.1.26/contrib/bind2nsd/chk_version0000664000175000017500000000271710647326614017446 0ustar wouterwouter#!/bin/sh # Copyright (c) 2007, Secure64 Software Corporation # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # # # see what version number we're at # SETUPV=$(grep -i version setup.py | sed 's/version = //' | sed "s/'//g" | \ sed 's/,//' | sed 's/[ ]*//g') echo "setup.py => ${SETUPV}" CONFIGV=$(grep -i version bind2nsd/Config.py | sed "s/'version'//" | \ sed "s/: '//" | sed "s/',//" | sed 's/[ \t]*//g') echo "bind2nsd/Config.py => ${CONFIGV}" nsd-4.1.26/contrib/nsd.init0000664000175000017500000001024211612245705015141 0ustar wouterwouter#!/bin/sh # # nsdc.sh -- a shell script to manage the beast # # Copyright (c) 2001-2006, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # (numbers are runlevels startpriority killpriority). # chkconfig: 2345 45 74 # description: NSD, authoritative only high performance name server. # configuration file default configfile="/etc/nsd.conf" # The directory where NSD binaries reside sbindir="/usr/sbin" # # You sure heard this many times before: NO USER SERVICEABLE PARTS BELOW # # see if user selects a different config file, with -c if test "x$1" = "x-c"; then shift if [ -e $1 ]; then configfile=$1 shift else echo "`basename $0`: Config file "$1" does not exist." exit 1 fi fi # locate nsd-checkconf : in sbindir, PATH, nsdc_dir or . nsd_checkconf="" if [ -e ${sbindir}/nsd-checkconf ]; then nsd_checkconf=${sbindir}/nsd-checkconf else if which nsd-checkconf >/dev/null 2>&1 ; then if which nsd-checkconf 2>&1 | grep "^[Nn]o " >/dev/null; then nsd_checkconf="" else nsd_checkconf=`which nsd-checkconf` fi fi if [ -z "${nsd_checkconf}" -a -e `dirname $0`/nsd-checkconf ]; then nsd_checkconf=`dirname $0`/nsd-checkconf fi if [ -z "${nsd_checkconf}" -a -e ./nsd-checkconf ]; then nsd_checkconf=./nsd-checkconf fi if [ -z "${nsd_checkconf}" ]; then echo "`basename $0`: Could not find nsd programs" \ "in $sbindir, in PATH=$PATH, in cwd=`pwd`," \ "or in dir of nsdc=`dirname $0`" exit 1 fi fi usage() { echo "Usage: `basename $0` [-c configfile] {start|stop|reload|restart|" echo " running}" echo "options:" echo " -c configfile Use specified configfile (default: @nsdconfigfile@)." echo "commands:" echo " start Start nsd server." echo " stop Stop nsd server." echo " reload Nsd server reloads database file." echo " restart Stop the nsd server and start it again." echo " running Prints message and exit nonzero if server not running." } # check the config syntax before using it ${nsd_checkconf} ${configfile} if test $? -ne 0 ; then usage exit 1 fi # Read some settings from the config file. pidfile=`${nsd_checkconf} -o pidfile ${configfile}` zonesdir=`${nsd_checkconf} -o zonesdir ${configfile}` sbindir=`dirname ${nsd_checkconf}` # move to zonesdir (if specified), and make absolute pathnames. if test -n "${zonesdir}"; then zonesdir=`dirname ${zonesdir}/.` if echo "${zonesdir}" | grep "^[^/]" >/dev/null; then zonesdir=`pwd`/${zonesdir} fi if echo "${pidfile}" | grep "^[^/]" >/dev/null; then pidfile=${zonesdir}/${pidfile} fi fi # for bash: -C or noclobber. For tcsh: noclobber. For bourne: -C. noclobber_set="set -C" # ugly check for tcsh if echo @shell@ | grep tcsh >/dev/null; then noclobber_set="set noclobber" fi # # useful routines # signal() { if [ -s ${pidfile} ] then kill -"$1" `cat ${pidfile}` && return 0 else echo "nsd is not running" fi return 1 } do_start() { if test -x ${sbindir}/nsd; then ${sbindir}/nsd -c ${configfile} test $? = 0 || (echo "nsd startup failed."; exit 1) else echo "${sbindir}/nsd not an executable file, nsd startup failed."; exit 1 fi } controlled_sleep() { if [ $1 -ge 25 ]; then sleep 1 fi } controlled_stop() { pid=$1 try=1 while [ $try -ne 0 ]; do if [ ${try} -gt 50 ]; then echo "nsdc stop failed" return 1 else if [ $try -eq 1 ]; then kill -TERM ${pid} else kill -TERM ${pid} >/dev/null 2>&1 fi # really stopped? kill -0 ${pid} >/dev/null 2>&1 if [ $? -eq 0 ]; then controlled_sleep ${try} try=`expr ${try} + 1` else try=0 fi fi done return 0 } do_controlled_stop() { if [ -s ${pidfile} ]; then pid=`cat ${pidfile}` controlled_stop ${pid} && return 0 else echo "nsd is not running, starting anyway" && return 0 fi return 1 } do_stop() { signal "TERM" } do_reload() { signal "HUP" } case "$1" in start) if test -s ${pidfile} && kill -"0" `cat ${pidfile}` then (echo "process `cat ${pidfile}` exists, please use restart"; exit 1) else do_start fi ;; stop) do_stop ;; stats) signal "USR1" ;; reload) do_reload ;; running) signal "0" ;; restart) do_controlled_stop && do_start ;; *) usage ;; esac exit $? nsd-4.1.26/contrib/nsd.spec0000664000175000017500000000607212614413737015143 0ustar wouterwouterSummary: NSD is a complete implementation of an authoritative DNS name server Name: nsd Version: 4.1.6 Release: 1%{?dist} License: BSD Url: http://www.nlnetlabs.nl/%{name}/ #Source: http://www.nlnetlabs.nl/downloads/%{name}/%{name}-%{version}.tar.gz Source: %{name}-%{version}.tar.gz Source1: nsd.init Source2: nsd.cron Group: System Environment/Daemons BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: flex, openssl-devel Requires(pre): shadow-utils %description NSD is a complete implementation of an authoritative DNS name server. It can function as a primary or secondary DNS server, with DNSSEC support. For further information about what NSD is and what NSD is not please consult the REQUIREMENTS document which is a part of this distribution. (thanks to Olaf). %prep %setup -q -n %{name}-%{version} %build %configure --enable-pie --enable-relro-now --enable-ratelimit \ --enable-bind8-stats --enable-plugins --enable-checking \ --enable-mmap --with-ssl --enable-nsec3 --enable-nsid \ --with-pidfile=%{_localstatedir}/run/%{name}/%{name}.pid --with-ssl \ --with-user=nsd --with-xfrdfile=%{_localstatedir}/lib/%{name}/ixfr.state %{__make} %{?_smp_mflags} #convert to utf8 iconv -f iso8859-1 -t utf-8 doc/RELNOTES > doc/RELNOTES.utf8 iconv -f iso8859-1 -t utf-8 doc/CREDITS > doc/CREDITS.utf8 mv -f doc/RELNOTES.utf8 doc/RELNOTES mv -f doc/CREDITS.utf8 doc/CREDITS %install rm -rf %{buildroot} %{__make} DESTDIR=%{buildroot} install install -d -m 0755 %{buildroot}%{_initrddir} install -d -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/cron.hourly install -c -m 0755 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/cron.hourly/nsd install -m 0755 %{SOURCE1} %{buildroot}/%{_initrddir}/nsd install -d -m 0700 %{buildroot}%{_localstatedir}/run/%{name} install -d -m 0700 %{buildroot}%{_localstatedir}/lib/%{name} # change .sample to normal config files head -76 %{buildroot}%{_sysconfdir}/nsd/nsd.conf.sample > %{buildroot}%{_sysconfdir}/nsd/nsd.conf rm %{buildroot}%{_sysconfdir}/nsd/nsd.conf.sample echo "database: /var/lib/nsd/nsd.db" >> %{buildroot}%{_sysconfdir}/nsd/nsd.conf echo "# include: \"/some/path/file\"" >> %{buildroot}%{_sysconfdir}/nsd/nsd.conf %clean rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root,-) %doc doc/* %doc contrib/nsd.zones2nsd.conf %dir %{_sysconfdir}/nsd/ %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/nsd/nsd.conf #%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/nsd/nsd.zones %attr(0755,root,root) %{_initrddir}/%{name} %{_sysconfdir}/cron.hourly/nsd %attr(0755,%{name},%{name}) %dir %{_localstatedir}/run/%{name} %attr(0755,%{name},%{name}) %dir %{_localstatedir}/lib/%{name} %{_sbindir}/* %{_mandir}/*/* %pre getent group nsd >/dev/null || groupadd -r nsd getent passwd nsd >/dev/null || \ useradd -r -g nsd -d /etc/nsd -s /sbin/nologin \ -c "nsd daemon account" nsd exit 0 %post /sbin/chkconfig --add %{name} %preun if [ $1 -eq 0 ]; then /sbin/service %{name} stop /sbin/chkconfig --del %{name} fi %postun if [ "$1" -ge "1" ]; then /sbin/service %{name} condrestart fi nsd-4.1.26/contrib/nsd.socket0000664000175000017500000000021713314402317015462 0ustar wouterwouter[Socket] ListenDatagram=127.0.0.1:1153 ListenStream=127.0.0.1:1153 # ListenStream=/usr/local/etc/nsd/control [Install] WantedBy=sockets.target nsd-4.1.26/contrib/README0000664000175000017500000000275613314402317014356 0ustar wouterwouterThis is NSD contributions directory and it contains various additions to NSD that are not a part of the official distribution but may be helpful. USE AT YOUR OWN RISK. * nsd.spec: a rpm specfile to generate binary and source rpms. Put the source tarball in /usr/src/redhat/SOURCES. Then rpmbuild -ba nsd.spec * nsd.init: a shell script that can start, stop, restart the NSD daemon. It uses signals, and can be used in rc.d init scripts (depends on platform). * nsd.zones2nsd.conf: a python script to convert NSD 2 nsd.zones config files to NSD 3 nsd.conf config files. Do not forget to set nsd_zones_name and key_dir variables at the top of the script. * bind2nsd: a slightly abridged form is included; find the full source at http://bind2nsd.sourceforge.net. The bind2nsd scripts translate DNS information in BIND format to NSD format, and then copy that translation to an NSD server. The goal is to make it simple to run redundant BIND and NSD servers and keep them in sync, using only the BIND configuration files * nsd_munin_ : plugin for munin statistics report You must have given --enable-bind8-stats (default is on) to configure. Copy the file to /usr/share/munin/plugins (or you munin node dir). You may also need to create a number of symbolic links under the names of the graphs you want to create (documented at head of file). * nsd.socket and nsd.service : example systemd service scripts for NSD. They are copies from Unbound's service files, edited for NSD. nsd-4.1.26/contrib/nsd.service0000664000175000017500000000137213314402317015635 0ustar wouterwouter[Unit] Description=Authoritative DNS Server Documentation=man:nsd(8) [Install] WantedBy=multi-user.target [Service] ExecReload=/bin/kill -HUP $MAINPID ExecStart=/usr/local/sbin/nsd NotifyAccess=main Type=notify CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT MemoryDenyWriteExecute=true NoNewPrivileges=true PrivateDevices=true PrivateTmp=true ProtectHome=true ProtectControlGroups=true ProtectKernelModules=true ProtectKernelTunables=true ProtectSystem=strict ReadWritePaths=/usr/local/etc /usr/local/var /run /usr/local/etc/nsd RestrictAddressFamilies=AF_INET AF_UNIX RestrictRealtime=true SystemCallArchitectures=native SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module mount @obsolete @resources nsd-4.1.26/contrib/nsd.zones2nsd.conf0000664000175000017500000000704710546466356017074 0ustar wouterwouter#!/usr/bin/env python # Contributed 2006 by Stephane Bortzmeyer. # Changed 20070102 by Wouter to handle primary zones and file names. # Converts a nsd 2 "nsd.zones" file to a nsd 3 "nsd.conf" file. # Change at will nsd_zones_name = "./nsd.zones" key_dir = "/local/nsd/etc/keys" # Directory holding the TSIG keys import re import os.path primary_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s*$", re.IGNORECASE) secondary_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s+masters\s+([0-9a-f:\. ]*)\s*$", re.IGNORECASE) notify_line_re = re.compile("^zone\s+([a-z0-9\.-]+)\s+([a-z0-9/\.-]+)\s+notify\s+([0-9a-f:\. ]*)\s*$", re.IGNORECASE) comment_re = re.compile("^\s*;") empty_re = re.compile("^\s*$") nsd_zones = open(nsd_zones_name) keys = {} for line in nsd_zones.xreadlines(): if comment_re.search(line) or empty_re.search(line): pass elif secondary_line_re.search(line): match = secondary_line_re.search(line) zone = match.group(1) zonefile = match.group(2) master_group = match.group(3) masters = re.split("\s+", master_group) print """zone: name: "%s" zonefile: "%s" # This is to allow "nsdc update" to work. allow-notify: 127.0.0.1 NOKEY # This is a slave zone. Masters are listed below.""" % (zone, zonefile) for master in masters: if re.search("^\s*$", master): continue key_filename = "%s/%s.tsiginfo" % (key_dir, master) if os.path.exists(key_filename): key_content = open(key_filename) peer_ip = key_content.readline() peer_ip = peer_ip[:-1] key_name = key_content.readline() key_name = key_name[:-1] algorithm = key_content.readline() algorithm = int(algorithm[:-1]) if algorithm == 157: algorithm_name = "hmac-md5" else: raise Exception("Unsupported TSIG algorithm %i" % algorithm) secret = key_content.readline() secret = secret[:-1] key_content.close() key = key_name keys[key_name] = { 'algorithm': algorithm_name, 'secret': secret} else: key = "NOKEY" print """ allow-notify: %s %s request-xfr: %s %s""" % (master, key, master, key) print "" elif primary_line_re.search(line): match = primary_line_re.search(line) zone = match.group(1) zonefile = match.group(2) print """zone: name: "%s" zonefile: "%s" """ % (zone, zonefile) elif notify_line_re.search(line): match = notify_line_re.search(line) zone = match.group(1) zonefile = match.group(2) notify_group = match.group(3) notifies = re.split("\s+", notify_group) print """zone: name: "%s" zonefile: "%s" # This is a master zone. Slaves are listed below.""" % (zone, zonefile) for notify in notifies: if re.search("^\s*$", notify): continue key = "NOKEY" print """ notify: %s %s""" % (notify, key) print "" else: raise Exception("Invalid line \"%s\"" % line) nsd_zones.close() for key in keys.keys(): print """key: name: "%s" algorithm: %s secret: "%s" """ % (key, keys[key]['algorithm'], keys[key]['secret']) print "" ## Local Variables: ## ## mode:python ## ## End: ## nsd-4.1.26/contrib/bug390.patch0000664000175000017500000000073012124021141015504 0ustar wouterwouterIndex: nsec3.c =================================================================== --- nsec3.c (revision 3889) +++ nsec3.c (working copy) @@ -820,6 +820,10 @@ if(!query->zone->nsec3_param) return; nsec3_add_nonexist_proof(query, answer, wildcard, qname); + if(wildcard->parent && wildcard->parent->nsec3 && + wildcard->parent->nsec3->nsec3_is_exact) + nsec3_add_rrset(query, answer, AUTHORITY_SECTION, + wildcard->parent->nsec3->nsec3_cover); } static void nsd-4.1.26/contrib/nsd_munin_0000775000175000017500000002722212452521627015560 0ustar wouterwouter#!/bin/sh # # plugin for munin to monitor usage of NSD. # # (C) 2008 W.C.A. Wijngaards. BSD Licensed. # # To install; compile with --enable-bind8-stats (enabled by default) # and enable nsd-control in nsd.conf with the line # remote-control: control-enable: yes # Run the command nsd-control-setup as root to generate the key files. # # Environment variables for this script # statefile - where to put temporary statefile. # nsd_conf - where the nsd.conf file is located. # nsd_control - where to find nsd-control executable. # nsd_checkconf - where to find nsd-checkconf executable. # # You can set them in your munin/plugin-conf.d/plugins.conf file # with: # [nsd_munin*] # user root # env.statefile /usr/local/var/munin/plugin-state/nsd-state # env.nsd_conf /usr/local/etc/nsd.conf # env.nsd_control /usr/local/sbin/nsd-control # env.nsd_checkconf /usr/local/sbin/nsd-checkconf # # This plugin can create different graphs depending on what name # you link it as (with ln -s) into the plugins directory # You can link it multiple times. # If you are only a casual user, the _hits and _by_type are most interesting, # possibly followed by _by_rcode. # # nsd_munin_hits - base volume, transport type, failures # nsd_munin_memory - memory usage # nsd_munin_by_type - incoming queries by type # nsd_munin_by_class - incoming queries by class # nsd_munin_by_opcode - incoming queries by opcode # nsd_munin_by_rcode - answers by rcode # nsd_munin_zones - number of zones # # Magic markers - optional - used by installation scripts and # munin-config: # #%# family=contrib #%# capabilities=autoconf suggest # POD documentation : <<=cut =head1 NAME nsd_munin_ - Munin plugin to monitor the NSD server. =head1 APPLICABLE SYSTEMS System with NSD daemon. =head1 CONFIGURATION [nsd_munin*] user root env.statefile /usr/local/var/munin/plugin-state/nsd-state env.nsd_conf /usr/local/etc/nsd.conf env.nsd_control /usr/local/sbin/nsd-control env.nsd_checkconf /usr/local/sbin/nsd-checkconf Use the .env settings to override the defaults. =head1 USAGE Can be used to present different graphs. Use ln -s for that name in the plugins directory to enable the graph. nsd_munin_hits - base volume, transport type, failures nsd_munin_memory - memory usage nsd_munin_by_type - incoming queries by type nsd_munin_by_class - incoming queries by class nsd_munin_by_opcode - incoming queries by opcode nsd_munin_by_rcode - answers by rcode nsd_munin_zones - number of zones =head1 AUTHOR Copyright 2008 W.C.A. Wijngaards =head1 LICENSE BSD =cut state=${statefile:-/usr/local/var/munin/plugin-state/nsd-state} conf=${nsd_conf:-/usr/local/etc/nsd.conf} ctrl=${nsd_control:-/usr/local/sbin/nsd-control} chkconf=${nsd_checkconf:-/usr/local/sbin/nsd-checkconf} lock=$state.lock # number of seconds between polling attempts. # makes the statefile hang around for at least this many seconds, # so that multiple links of this script can share the results. lee=55 # to keep things within 19 characters ABBREV="-e s/num/n/ -e s/type/t/ -e s/opcode/o/ -e s/rcode/r/ -e s/class/c/" # get value from $1 into return variable $value get_value ( ) { value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`" if test "$value"x = ""x; then value="0" fi } # download the state from NSD. get_state ( ) { # obtain lock for fetching the state # because there is a race condition in fetching and writing to file # see if the lock is stale, if so, take it if test -f $lock ; then pid="`cat $lock 2>&1`" kill -0 "$pid" >/dev/null 2>&1 if test $? -ne 0 -a "$pid" != $$ ; then echo $$ >$lock fi fi i=0 while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do while test -f $lock; do # wait i=`expr $i + 1` if test $i -gt 1000; then sleep 1; fi if test $i -gt 1500; then echo "error locking $lock" "=" `cat $lock` rm -f $lock exit 1 fi done # try to get it echo $$ >$lock done # do not refetch if the file exists and only LEE seconds old if test -f $state; then now=`date +%s` get_value "timestamp" if test $now -lt `expr $value + $lee`; then rm -f $lock return fi fi $ctrl -c $conf stats > $state if test $? -ne 0; then echo "error retrieving data from the server" rm -f $lock exit 1 fi echo "timestamp="`date +%s` >> $state rm -f $lock } if test "$1" = "autoconf" ; then if test ! -f $conf; then echo no "($conf does not exist)" exit 1 fi if test ! -d `dirname $state`; then mkdir -p `dirname $state` if test ! -d `dirname $state`; then echo no "($state directory does not exist)" exit 1 fi fi echo yes exit 0 fi if test "$1" = "suggest" ; then echo "hits" echo "memory" echo "by_type" echo "by_class" echo "by_opcode" echo "by_rcode" echo "zones" exit 0 fi # determine my type, by name id=`echo $0 | sed -e 's/^.*nsd_munin_//'` if test "$id"x = ""x; then # some default to keep people sane. id="hits" fi # if $1 exists in statefile, config is echoed with label $2 exist_config ( ) { mn=`echo $1 | sed $ABBREV | tr . _` if grep '^'$1'=' $state >/dev/null 2>&1; then echo "$mn.label $2" echo "$mn.min 0" echo "$mn.type ABSOLUTE" fi } # print label and min 0 for a name $1 in nsd format p_config ( ) { mn=`echo $1 | sed $ABBREV | tr . _` echo $mn.label "$2" echo $mn.min 0 echo $mn.type $3 } if test "$1" = "config" ; then if test ! -f $state; then get_state fi case $id in hits) echo "graph_title NSD traffic" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in server0.queries server1.queries server2.queries \ server3.queries server4.queries server5.queries \ server6.queries server7.queries server8.queries \ server9.queries server10.queries server11.queries \ server12.queries server13.queries server14.queries \ server15.queries ; do exist_config $x "queries handled by `basename $x .queries`" done p_config "num.queries" "total queries" "ABSOLUTE" p_config "num.udp" "UDP ip4 queries" "ABSOLUTE" p_config "num.udp6" "UDP ip6 queries" "ABSOLUTE" p_config "num.tcp" "TCP ip4 queries" "ABSOLUTE" p_config "num.tcp6" "TCP ip6 queries" "ABSOLUTE" p_config "num.edns" "queries with EDNS OPT" "ABSOLUTE" p_config "num.ednserr" "queries failed EDNS parse" "ABSOLUTE" p_config "num.answer_wo_aa" "nonauthor. queries (referrals)" "ABSOLUTE" p_config "num.rxerr" "receive failed" "ABSOLUTE" p_config "num.txerr" "transmit failed" "ABSOLUTE" p_config "num.truncated" "truncated replies with TC" "ABSOLUTE" p_config "num.raxfr" "AXFR from allowed client" "ABSOLUTE" p_config "num.dropped" "dropped due to sanity check" "ABSOLUTE" echo "graph_info DNS queries." ;; memory) echo "graph_title NSD memory usage" echo "graph_args --base 1024 -l 0" echo "graph_vlabel memory used in bytes" echo "graph_category DNS" p_config "size.vsz" "Total virtual memory (VSZ)" "GAUGE" p_config "size.rss" "Total resident memory (RSS)" "GAUGE" p_config "size.db.mem" "data in memory" "GAUGE" p_config "size.xfrd.mem" "xfr and notify memory" "GAUGE" p_config "size.config.mem" "config memory" "GAUGE" p_config "size.db.disk" "mmap of nsd.db file" "GAUGE" p_config "size.config.disk" "config zonelist on disk" "GAUGE" echo "graph_info The memory used by NSD, xfrd and config. Disk size of nsd.db and zonelist." ;; by_type) echo "graph_title NSD queries by type" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.type" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.type.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by DNS RR type queried for" ;; by_class) echo "graph_title NSD queries by class" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.class" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.class.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by DNS RR class queried for." ;; by_opcode) echo "graph_title NSD queries by opcode" echo "graph_args --base 1000 -l 0" echo "graph_vlabel queries / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.opcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.opcode.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info queries by opcode in the query packet." ;; by_rcode) echo "graph_title NSD answers by return code" echo "graph_args --base 1000 -l 0" echo "graph_vlabel answer packets / \${graph_period}" echo "graph_scale no" echo "graph_category DNS" for x in `grep "^num.rcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` tp=`echo $nm | sed -e s/num.rcode.//` p_config "$nm" "$tp" "ABSOLUTE" done echo "graph_info answers split out by return value." ;; zones) echo "graph_title NSD number of zones" echo "graph_args --base 1000 -l 0" echo "graph_vlabel zone count" echo "graph_category DNS" p_config "zone.total" "total zones" "GAUGE" p_config "zone.master" "master zones" "GAUGE" p_config "zone.slave" "slave zones" "GAUGE" echo "graph_info number of zones served by NSD." ;; esac exit 0 fi # do the stats itself get_state # get the time elapsed get_value "time.elapsed" if test $value = 0 || test $value = "0.000000"; then echo "error: time elapsed 0 or could not retrieve data" exit 1 fi elapsed="$value" # print value for $1 print_value ( ) { mn=`echo $1 | sed $ABBREV | tr . _` get_value $1 echo "$mn.value" $value } # print value if line already found in $2 print_value_line ( ) { mn=`echo $1 | sed $ABBREV | tr . _` value="`echo $2 | sed -e 's/^.*=//'`" echo "$mn.value" $value } case $id in hits) for x in server0.queries server1.queries server2.queries \ server3.queries server4.queries server5.queries \ server6.queries server7.queries server8.queries \ server9.queries server10.queries server11.queries \ server12.queries server13.queries server14.queries \ server15.queries \ num.queries num.udp num.udp6 num.tcp num.tcp6 \ num.edns num.ednserr num.answer_wo_aa num.rxerr num.txerr \ num.truncated num.raxfr num.dropped ; do if grep "^"$x"=" $state >/dev/null 2>&1; then print_value $x fi done ;; memory) # get the total memory for NSD serverpid=`$ctrl -c $conf serverpid 2>&1` # small race condition, if reload happens between previous and next # lines, if so, detect by checking if we have a number as output. rssval=`ps -p $serverpid -o rss= 2>&1` vszval=`ps -p $serverpid -o vsz= 2>&1` if test "`expr $rssval + 1 - 1 2>&1`" -eq "$rssval" >/dev/null 2>&1; then rssval=`expr $rssval \* 1024` else rssval=0 fi if test "`expr $vszval + 1 - 1 2>&1`" -eq "$vszval" >/dev/null 2>&1; then vszval=`expr $vszval \* 1024` else vszval=0 fi echo "size_vsz.value" $vszval echo "size_rss.value" $rssval for x in size.db.mem size.xfrd.mem size.config.mem \ size.db.disk size.config.disk; do print_value $x done ;; by_type) for x in `grep "^num.type" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_class) for x in `grep "^num.class" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_opcode) for x in `grep "^num.opcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; by_rcode) for x in `grep "^num.rcode" $state`; do nm=`echo $x | sed -e 's/=.*$//'` print_value_line $nm $x done ;; zones) get_value "zone.master" nummas="$value" get_value "zone.slave" numsla="$value" echo "zone_total.value" `expr $nummas + $numsla` echo "zone_master.value" "$nummas" echo "zone_slave.value" "$numsla" esac nsd-4.1.26/rrl.h0000664000175000017500000000464113241307322013000 0ustar wouterwouter/* rrl.h - Response Rate Limiting for NSD. * By W.C.A. Wijngaards * Copyright 2012, NLnet Labs. * BSD, see LICENSE. */ #ifndef RRL_H #define RRL_H #include "query.h" /** the classification types for the rrl */ enum rrl_type { /* classification types */ rrl_type_nxdomain = 0x01, rrl_type_error = 0x02, rrl_type_referral = 0x04, rrl_type_any = 0x08, rrl_type_wildcard = 0x10, rrl_type_nodata = 0x20, rrl_type_dnskey = 0x40, rrl_type_positive = 0x80, rrl_type_rrsig = 0x100, /* all classification types */ rrl_type_all = 0x1ff, /* to distinguish between ip4 and ip6 netblocks, used in code */ rrl_ip6 = 0x8000 }; /** Number of buckets */ #define RRL_BUCKETS 1000000 /** default rrl limit, in 2x qps , the default is 200 qps */ #define RRL_LIMIT 400 /** default slip */ #define RRL_SLIP 2 /** default prefix lengths */ #define RRL_IPV4_PREFIX_LENGTH 24 #define RRL_IPV6_PREFIX_LENGTH 64 /** default whitelist rrl limit, in 2x qps, default is thus 2000 qps */ #define RRL_WLIST_LIMIT 4000 /** * Initialize for n children (optional, otherwise no mmaps used) * ratelimits lm and wlm are in qps (this routines x2s them for internal use). * plf and pls are in prefix lengths. */ void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm, size_t plf, size_t pls); /** * Initialize rate limiting (for this child server process) */ void rrl_init(size_t ch); /** deinit (for this child server processs) */ void rrl_deinit(size_t ch); /** deinit mmaps for n children */ void rrl_mmap_deinit(void); /** frees memory but keeps mmap in place (for other processes) */ void rrl_mmap_deinit_keep_mmap(void); /** * Process query that happens, the query structure contains the * information about the query and the answer. * returns true if the query is ratelimited. */ int rrl_process_query(query_type* query); /** * Deny the query, with slip. * Returns DISCARD or PROCESSED(with TC flag). */ query_state_type rrl_slip(query_type* query); /** convert classification type to string */ const char* rrltype2str(enum rrl_type c); /** convert string to classification type */ enum rrl_type rrlstr2type(const char* s); /** for unit test, update rrl bucket; return rate */ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, uint16_t flags, int32_t now, uint32_t lm); /** set the rate limit counters, pass variables in qps */ void rrl_set_limit(size_t lm, size_t wlm, size_t sm); #endif /* RRL_H */ nsd-4.1.26/answer.c0000664000175000017500000000512712715075517013510 0ustar wouterwouter/* * answer.c -- manipulating query answers and encoding them. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include "answer.h" #include "packet.h" #include "query.h" void answer_init(answer_type *answer) { answer->rrset_count = 0; } int answer_add_rrset(answer_type *answer, rr_section_type section, domain_type *domain, rrset_type *rrset) { size_t i; assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT); assert(domain); assert(rrset); /* Don't add an RRset multiple times. */ for (i = 0; i < answer->rrset_count; ++i) { if (answer->rrsets[i] == rrset && answer->domains[i]->number == domain->number) { if (section < answer->section[i]) { answer->section[i] = section; return 1; } else { return 0; } } } if (answer->rrset_count >= MAXRRSPP) { /* XXX: Generate warning/error? */ return 0; } answer->section[answer->rrset_count] = section; answer->domains[answer->rrset_count] = domain; answer->rrsets[answer->rrset_count] = rrset; ++answer->rrset_count; return 1; } void encode_answer(query_type *q, const answer_type *answer) { uint16_t counts[RR_SECTION_COUNT]; rr_section_type section; size_t i; int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE; int done = 0; #if defined(INET6) && defined(MINIMAL_RESPONSES) if (q->addr.ss_family == AF_INET6) minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE; #endif for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) { counts[section] = 0; } for (section = ANSWER_SECTION; !TC(q->packet) && section < RR_SECTION_COUNT; ++section) { for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) { if (answer->section[i] == section) { counts[section] += packet_encode_rrset( q, answer->domains[i], answer->rrsets[i], section, minimal_respsize, &done); } } #ifdef MINIMAL_RESPONSES /** * done is set prematurely, because the minimal response size * has been reached. No need to try adding RRsets in following * sections. */ if (done) { /* delegations should have a usable address in it */ if(section == ADDITIONAL_A_SECTION && counts[ADDITIONAL_A_SECTION] == 0 && q->delegation_domain) TC_SET(q->packet); break; } #endif } ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]); NSCOUNT_SET(q->packet, counts[AUTHORITY_SECTION] + counts[OPTIONAL_AUTHORITY_SECTION]); ARCOUNT_SET(q->packet, counts[ADDITIONAL_A_SECTION] + counts[ADDITIONAL_AAAA_SECTION] + counts[ADDITIONAL_OTHER_SECTION]); } nsd-4.1.26/zparser.y0000664000175000017500000011274613377253142013730 0ustar wouterwouter%{ /* * zyparser.y -- yacc grammar for (DNS) zone files * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include "dname.h" #include "namedb.h" #include "zonec.h" /* these need to be global, otherwise they cannot be used inside yacc */ zparser_type *parser; #ifdef __cplusplus extern "C" #endif /* __cplusplus */ int yywrap(void); /* this hold the nxt bits */ static uint8_t nxtbits[16]; static int dlv_warn = 1; /* 256 windows of 256 bits (32 bytes) */ /* still need to reset the bastard somewhere */ static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE]; /* hold the highest rcode seen in a NSEC rdata , BUG #106 */ uint16_t nsec_highest_rcode; void yyerror(const char *message); #ifdef NSEC3 /* parse nsec3 parameters and add the (first) rdata elements */ static void nsec3_add_params(const char* hash_algo_str, const char* flag_str, const char* iter_str, const char* salt_str, int salt_len); #endif /* NSEC3 */ %} %union { domain_type *domain; const dname_type *dname; struct lex_data data; uint32_t ttl; uint16_t klass; uint16_t type; uint16_t *unknown; } /* * Tokens to represent the known RR types of DNS. */ %token T_A T_NS T_MX T_TXT T_CNAME T_AAAA T_PTR T_NXT T_KEY T_SOA T_SIG %token T_SRV T_CERT T_LOC T_MD T_MF T_MB T_MG T_MR T_NULL T_WKS T_HINFO %token T_MINFO T_RP T_AFSDB T_X25 T_ISDN T_RT T_NSAP T_NSAP_PTR T_PX %token T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK %token T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR %token T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY %token T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA T_URI %token T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY %token T_OPENPGPKEY T_CSYNC T_AVC T_SMIMEA /* other tokens */ %token DOLLAR_TTL DOLLAR_ORIGIN NL SP %token STR PREV BITLAB %token T_TTL %token T_RRCLASS /* unknown RRs */ %token URR %token T_UTYPE %type type_and_rdata %type owner dname abs_dname %type rel_dname label %type wire_dname wire_abs_dname wire_rel_dname wire_label %type concatenated_str_seq str_sp_seq str_dot_seq dotted_str %type nxt_seq nsec_more %type rdata_unknown %% lines: /* empty file */ | lines line ; line: NL | sp NL | PREV NL {} /* Lines containing only whitespace. */ | ttl_directive { region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } | origin_directive { region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } | rr { /* rr should be fully parsed */ if (!parser->error_occurred) { parser->current_rr.rdatas =(rdata_atom_type *)region_alloc_array_init( parser->region, parser->current_rr.rdatas, parser->current_rr.rdata_count, sizeof(rdata_atom_type)); process_rr(); } region_free_all(parser->rr_region); parser->current_rr.type = 0; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } | error NL ; /* needed to cope with ( and ) in arbitrary places */ sp: SP | sp SP ; trail: NL | sp NL ; ttl_directive: DOLLAR_TTL sp STR trail { parser->default_ttl = zparser_ttl2int($3.str, &(parser->error_occurred)); if (parser->error_occurred == 1) { parser->default_ttl = DEFAULT_TTL; parser->error_occurred = 0; } } ; origin_directive: DOLLAR_ORIGIN sp abs_dname trail { /* if previous origin is unused, remove it, do not leak it */ if(parser->origin != error_domain && parser->origin != $3) { /* protect $3 from deletion, because deldomain walks up */ $3->usage ++; domain_table_deldomain(parser->db, parser->origin); $3->usage --; } parser->origin = $3; } | DOLLAR_ORIGIN sp rel_dname trail { zc_error_prev_line("$ORIGIN directive requires absolute domain name"); } ; rr: owner classttl type_and_rdata { parser->current_rr.owner = $1; parser->current_rr.type = $3; } ; owner: dname sp { parser->prev_dname = $1; $$ = $1; } | PREV { $$ = parser->prev_dname; } ; classttl: /* empty - fill in the default, def. ttl and IN class */ { parser->current_rr.ttl = parser->default_ttl; parser->current_rr.klass = parser->default_class; } | T_RRCLASS sp /* no ttl */ { parser->current_rr.ttl = parser->default_ttl; parser->current_rr.klass = $1; } | T_TTL sp /* no class */ { parser->current_rr.ttl = $1; parser->current_rr.klass = parser->default_class; } | T_TTL sp T_RRCLASS sp /* the lot */ { parser->current_rr.ttl = $1; parser->current_rr.klass = $3; } | T_RRCLASS sp T_TTL sp /* the lot - reversed */ { parser->current_rr.ttl = $3; parser->current_rr.klass = $1; } ; dname: abs_dname | rel_dname { if ($1 == error_dname) { $$ = error_domain; } else if(parser->origin == error_domain) { zc_error("cannot concatenate origin to domain name, because origin failed to parse"); $$ = error_domain; } else if ($1->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) { zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$ = error_domain; } else { $$ = domain_table_insert( parser->db->domains, dname_concatenate( parser->rr_region, $1, domain_dname(parser->origin))); } } ; abs_dname: '.' { $$ = parser->db->domains->root; } | '@' { $$ = parser->origin; } | rel_dname '.' { if ($1 != error_dname) { $$ = domain_table_insert(parser->db->domains, $1); } else { $$ = error_domain; } } ; label: STR { if ($1.len > MAXLABELLEN) { zc_error("label exceeds %d character limit", MAXLABELLEN); $$ = error_dname; } else if ($1.len <= 0) { zc_error("zero label length"); $$ = error_dname; } else { $$ = dname_make_from_label(parser->rr_region, (uint8_t *) $1.str, $1.len); } } | BITLAB { zc_error("bitlabels are now deprecated. RFC2673 is obsoleted."); $$ = error_dname; } ; rel_dname: label | rel_dname '.' label { if ($1 == error_dname || $3 == error_dname) { $$ = error_dname; } else if ($1->name_size + $3->name_size - 1 > MAXDOMAINLEN) { zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$ = error_dname; } else { $$ = dname_concatenate(parser->rr_region, $1, $3); } } ; /* * Some dnames in rdata are handled as opaque blobs */ wire_dname: wire_abs_dname | wire_rel_dname { /* terminate in root label and copy the origin in there */ if(parser->origin && domain_dname(parser->origin)) { $$.len = $1.len + domain_dname(parser->origin)->name_size; if ($$.len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$.str = (char *) region_alloc(parser->rr_region, $$.len); memmove($$.str, $1.str, $1.len); memmove($$.str + $1.len, dname_name(domain_dname(parser->origin)), domain_dname(parser->origin)->name_size); } else { $$.len = $1.len + 1; if ($$.len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$.str = (char *) region_alloc(parser->rr_region, $$.len); memmove($$.str, $1.str, $1.len); $$.str[ $1.len ] = 0; } } ; wire_abs_dname: '.' { char *result = (char *) region_alloc(parser->rr_region, 1); result[0] = 0; $$.str = result; $$.len = 1; } | '@' { if(parser->origin && domain_dname(parser->origin)) { $$.len = domain_dname(parser->origin)->name_size; $$.str = (char *) region_alloc(parser->rr_region, $$.len); memmove($$.str, dname_name(domain_dname(parser->origin)), $$.len); } else { $$.len = 1; $$.str = (char *) region_alloc(parser->rr_region, $$.len); $$.str[0] = 0; } } | wire_rel_dname '.' { $$.len = $1.len + 1; if ($$.len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$.str = (char *) region_alloc(parser->rr_region, $$.len); memcpy($$.str, $1.str, $1.len); $$.str[$1.len] = 0; } ; wire_label: STR { char *result = (char *) region_alloc(parser->rr_region, $1.len + 1); if ($1.len > MAXLABELLEN) zc_error("label exceeds %d character limit", MAXLABELLEN); /* make label anyway */ result[0] = $1.len; memmove(result+1, $1.str, $1.len); $$.str = result; $$.len = $1.len + 1; } ; wire_rel_dname: wire_label | wire_rel_dname '.' wire_label { $$.len = $1.len + $3.len; if ($$.len > MAXDOMAINLEN) zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$.str = (char *) region_alloc(parser->rr_region, $$.len); memmove($$.str, $1.str, $1.len); memmove($$.str + $1.len, $3.str, $3.len); } ; str_seq: dotted_str { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1); } | str_seq sp dotted_str { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0); } ; /* * Generate a single string from multiple STR tokens, separated by * spaces or dots. */ concatenated_str_seq: STR | '.' { $$.len = 1; $$.str = region_strdup(parser->rr_region, "."); } | concatenated_str_seq sp STR { $$.len = $1.len + $3.len + 1; $$.str = (char *) region_alloc(parser->rr_region, $$.len + 1); memcpy($$.str, $1.str, $1.len); memcpy($$.str + $1.len, " ", 1); memcpy($$.str + $1.len + 1, $3.str, $3.len); $$.str[$$.len] = '\0'; } | concatenated_str_seq '.' STR { $$.len = $1.len + $3.len + 1; $$.str = (char *) region_alloc(parser->rr_region, $$.len + 1); memcpy($$.str, $1.str, $1.len); memcpy($$.str + $1.len, ".", 1); memcpy($$.str + $1.len + 1, $3.str, $3.len); $$.str[$$.len] = '\0'; } ; /* used to convert a nxt list of types */ nxt_seq: STR { uint16_t type = rrtype_from_string($1.str); if (type != 0 && type < 128) { set_bit(nxtbits, type); } else { zc_error("bad type %d in NXT record", (int) type); } } | nxt_seq sp STR { uint16_t type = rrtype_from_string($3.str); if (type != 0 && type < 128) { set_bit(nxtbits, type); } else { zc_error("bad type %d in NXT record", (int) type); } } ; nsec_more: SP nsec_more { } | NL { } | STR nsec_seq { uint16_t type = rrtype_from_string($1.str); if (type != 0) { if (type > nsec_highest_rcode) { nsec_highest_rcode = type; } set_bitnsec(nsecbits, type); } else { zc_error("bad type %d in NSEC record", (int) type); } } ; nsec_seq: NL | SP nsec_more ; /* * Sequence of STR tokens separated by spaces. The spaces are not * preserved during concatenation. */ str_sp_seq: STR | str_sp_seq sp STR { char *result = (char *) region_alloc(parser->rr_region, $1.len + $3.len + 1); memcpy(result, $1.str, $1.len); memcpy(result + $1.len, $3.str, $3.len); $$.str = result; $$.len = $1.len + $3.len; $$.str[$$.len] = '\0'; } ; /* * Sequence of STR tokens separated by dots. The dots are not * preserved during concatenation. */ str_dot_seq: STR | str_dot_seq '.' STR { char *result = (char *) region_alloc(parser->rr_region, $1.len + $3.len + 1); memcpy(result, $1.str, $1.len); memcpy(result + $1.len, $3.str, $3.len); $$.str = result; $$.len = $1.len + $3.len; $$.str[$$.len] = '\0'; } ; /* * A string that can contain dots. */ dotted_str: STR | '.' { $$.str = "."; $$.len = 1; } | dotted_str '.' { char *result = (char *) region_alloc(parser->rr_region, $1.len + 2); memcpy(result, $1.str, $1.len); result[$1.len] = '.'; $$.str = result; $$.len = $1.len + 1; $$.str[$$.len] = '\0'; } | dotted_str '.' STR { char *result = (char *) region_alloc(parser->rr_region, $1.len + $3.len + 2); memcpy(result, $1.str, $1.len); result[$1.len] = '.'; memcpy(result + $1.len + 1, $3.str, $3.len); $$.str = result; $$.len = $1.len + $3.len + 1; $$.str[$$.len] = '\0'; } ; /* define what we can parse */ type_and_rdata: /* * All supported RR types. We don't support NULL and types marked obsolete. */ T_A sp rdata_a | T_A sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NS sp rdata_domain_name | T_NS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_MD sp rdata_domain_name { zc_warning_prev_line("MD is obsolete"); } | T_MD sp rdata_unknown { zc_warning_prev_line("MD is obsolete"); $$ = $1; parse_unknown_rdata($1, $3); } | T_MF sp rdata_domain_name { zc_warning_prev_line("MF is obsolete"); } | T_MF sp rdata_unknown { zc_warning_prev_line("MF is obsolete"); $$ = $1; parse_unknown_rdata($1, $3); } | T_CNAME sp rdata_domain_name | T_CNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_SOA sp rdata_soa | T_SOA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_MB sp rdata_domain_name { zc_warning_prev_line("MB is obsolete"); } | T_MB sp rdata_unknown { zc_warning_prev_line("MB is obsolete"); $$ = $1; parse_unknown_rdata($1, $3); } | T_MG sp rdata_domain_name | T_MG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_MR sp rdata_domain_name | T_MR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } /* NULL */ | T_WKS sp rdata_wks | T_WKS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_PTR sp rdata_domain_name | T_PTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_HINFO sp rdata_hinfo | T_HINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_MINFO sp rdata_minfo /* Experimental */ | T_MINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_MX sp rdata_mx | T_MX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_TXT sp rdata_txt | T_TXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_SPF sp rdata_txt | T_SPF sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_AVC sp rdata_txt | T_AVC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_RP sp rdata_rp /* RFC 1183 */ | T_RP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_AFSDB sp rdata_afsdb /* RFC 1183 */ | T_AFSDB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_X25 sp rdata_x25 /* RFC 1183 */ | T_X25 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_ISDN sp rdata_isdn /* RFC 1183 */ | T_ISDN sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_IPSECKEY sp rdata_ipseckey /* RFC 4025 */ | T_IPSECKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DHCID sp rdata_dhcid | T_DHCID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_RT sp rdata_rt /* RFC 1183 */ | T_RT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NSAP sp rdata_nsap /* RFC 1706 */ | T_NSAP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_SIG sp rdata_rrsig | T_SIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_KEY sp rdata_dnskey | T_KEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_PX sp rdata_px /* RFC 2163 */ | T_PX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_AAAA sp rdata_aaaa | T_AAAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_LOC sp rdata_loc | T_LOC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NXT sp rdata_nxt | T_NXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_SRV sp rdata_srv | T_SRV sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NAPTR sp rdata_naptr /* RFC 2915 */ | T_NAPTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_KX sp rdata_kx /* RFC 2230 */ | T_KX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CERT sp rdata_cert /* RFC 2538 */ | T_CERT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DNAME sp rdata_domain_name /* RFC 2672 */ | T_DNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_APL trail /* RFC 3123 */ | T_APL sp rdata_apl /* RFC 3123 */ | T_APL sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DS sp rdata_ds | T_DS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DLV sp rdata_dlv { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } } | T_DLV sp rdata_unknown { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } $$ = $1; parse_unknown_rdata($1, $3); } | T_SSHFP sp rdata_sshfp | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_RRSIG sp rdata_rrsig | T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NSEC sp rdata_nsec | T_NSEC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NSEC3 sp rdata_nsec3 | T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NSEC3PARAM sp rdata_nsec3_param | T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DNSKEY sp rdata_dnskey | T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_TLSA sp rdata_tlsa | T_TLSA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_SMIMEA sp rdata_smimea | T_SMIMEA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NID sp rdata_nid | T_NID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_L32 sp rdata_l32 | T_L32 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_L64 sp rdata_l64 | T_L64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_LP sp rdata_lp | T_LP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_EUI48 sp rdata_eui48 | T_EUI48 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_EUI64 sp rdata_eui64 | T_EUI64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CAA sp rdata_caa | T_CAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CDS sp rdata_ds | T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CDNSKEY sp rdata_dnskey | T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_OPENPGPKEY sp rdata_openpgpkey | T_OPENPGPKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CSYNC sp rdata_csync | T_CSYNC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_URI sp rdata_uri | T_URI sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | STR error NL { zc_error_prev_line("unrecognized RR type '%s'", $1.str); } ; /* * * below are all the definition for all the different rdata * */ rdata_a: dotted_str trail { zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str)); } ; rdata_domain_name: dname trail { /* convert a single dname record */ zadd_rdata_domain($1); } ; rdata_soa: dname sp dname sp STR sp STR sp STR sp STR sp STR trail { /* convert the soa data */ zadd_rdata_domain($1); /* prim. ns */ zadd_rdata_domain($3); /* email */ zadd_rdata_wireformat(zparser_conv_serial(parser->region, $5.str)); /* serial */ zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* refresh */ zadd_rdata_wireformat(zparser_conv_period(parser->region, $9.str)); /* retry */ zadd_rdata_wireformat(zparser_conv_period(parser->region, $11.str)); /* expire */ zadd_rdata_wireformat(zparser_conv_period(parser->region, $13.str)); /* minimum */ } ; rdata_wks: dotted_str sp STR sp concatenated_str_seq trail { zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str)); /* address */ zadd_rdata_wireformat(zparser_conv_services(parser->region, $3.str, $5.str)); /* protocol and services */ } ; rdata_hinfo: STR sp STR trail { zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* CPU */ zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* OS*/ } ; rdata_minfo: dname sp dname trail { /* convert a single dname record */ zadd_rdata_domain($1); zadd_rdata_domain($3); } ; rdata_mx: STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */ zadd_rdata_domain($3); /* MX host */ } ; rdata_txt: str_seq trail { zadd_rdata_txt_clean_wireformat(); } ; /* RFC 1183 */ rdata_rp: dname sp dname trail { zadd_rdata_domain($1); /* mbox d-name */ zadd_rdata_domain($3); /* txt d-name */ } ; /* RFC 1183 */ rdata_afsdb: STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* subtype */ zadd_rdata_domain($3); /* domain name */ } ; /* RFC 1183 */ rdata_x25: STR trail { zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* X.25 address. */ } ; /* RFC 1183 */ rdata_isdn: STR trail { zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */ } | STR sp STR trail { zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */ zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* sub-address */ } ; /* RFC 1183 */ rdata_rt: STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_domain($3); /* intermediate host */ } ; /* RFC 1706 */ rdata_nsap: str_dot_seq trail { /* String must start with "0x" or "0X". */ if (strncasecmp($1.str, "0x", 2) != 0) { zc_error_prev_line("NSAP rdata must start with '0x'"); } else { zadd_rdata_wireformat(zparser_conv_hex(parser->region, $1.str + 2, $1.len - 2)); /* NSAP */ } } ; /* RFC 2163 */ rdata_px: STR sp dname sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_domain($3); /* MAP822 */ zadd_rdata_domain($5); /* MAPX400 */ } ; rdata_aaaa: dotted_str trail { zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $1.str)); /* IPv6 address */ } ; rdata_loc: concatenated_str_seq trail { zadd_rdata_wireformat(zparser_conv_loc(parser->region, $1.str)); /* Location */ } ; rdata_nxt: dname sp nxt_seq trail { zadd_rdata_domain($1); /* nxt name */ zadd_rdata_wireformat(zparser_conv_nxt(parser->region, nxtbits)); /* nxt bitlist */ memset(nxtbits, 0, sizeof(nxtbits)); } ; rdata_srv: STR sp STR sp STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* prio */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $5.str)); /* port */ zadd_rdata_domain($7); /* target name */ } ; /* RFC 2915 */ rdata_naptr: STR sp STR sp STR sp STR sp STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* order */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* preference */ zadd_rdata_wireformat(zparser_conv_text(parser->region, $5.str, $5.len)); /* flags */ zadd_rdata_wireformat(zparser_conv_text(parser->region, $7.str, $7.len)); /* service */ zadd_rdata_wireformat(zparser_conv_text(parser->region, $9.str, $9.len)); /* regexp */ zadd_rdata_domain($11); /* target name */ } ; /* RFC 2230 */ rdata_kx: STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_domain($3); /* exchanger */ } ; /* RFC 2538 */ rdata_cert: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_certificate_type(parser->region, $1.str)); /* type */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* key tag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* algorithm */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* certificate or CRL */ } ; /* RFC 3123 */ rdata_apl: rdata_apl_seq trail ; rdata_apl_seq: dotted_str { zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $1.str)); } | rdata_apl_seq sp dotted_str { zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $3.str)); } ; rdata_ds: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */ } ; rdata_dlv: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */ } ; rdata_sshfp: STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* fp type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, $5.str, $5.len)); /* hash */ } ; rdata_dhcid: str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str)); /* data blob */ } ; rdata_rrsig: STR sp STR sp STR sp STR sp STR sp STR sp STR sp wire_dname sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_rrtype(parser->region, $1.str)); /* rr covered */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* # labels */ zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* # orig TTL */ zadd_rdata_wireformat(zparser_conv_time(parser->region, $9.str)); /* sig exp */ zadd_rdata_wireformat(zparser_conv_time(parser->region, $11.str)); /* sig inc */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $13.str)); /* key id */ zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, (const uint8_t*) $15.str,$15.len)); /* sig name */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, $17.str)); /* sig data */ } ; rdata_nsec: wire_dname nsec_seq { zadd_rdata_wireformat(zparser_conv_dns_name(parser->region, (const uint8_t*) $1.str, $1.len)); /* nsec name */ zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; } ; rdata_nsec3: STR sp STR sp STR sp STR sp STR nsec_seq { #ifdef NSEC3 nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len); zadd_rdata_wireformat(zparser_conv_b32(parser->region, $9.str)); /* next hashed name */ zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; #else zc_error_prev_line("nsec3 not supported"); #endif /* NSEC3 */ } ; rdata_nsec3_param: STR sp STR sp STR sp STR trail { #ifdef NSEC3 nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len); #else zc_error_prev_line("nsec3 not supported"); #endif /* NSEC3 */ } ; rdata_tlsa: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */ } ; rdata_smimea: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */ zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */ } ; rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* flags */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* proto */ zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* alg */ zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* hash */ } ; rdata_ipsec_base: STR sp STR sp STR sp dotted_str { const dname_type* name = 0; zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* precedence */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* gateway type */ zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* algorithm */ switch(atoi($3.str)) { case IPSECKEY_NOGATEWAY: zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 0)); break; case IPSECKEY_IP4: zadd_rdata_wireformat(zparser_conv_a(parser->region, $7.str)); break; case IPSECKEY_IP6: zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $7.str)); break; case IPSECKEY_DNAME: /* convert and insert the dname */ if(strlen($7.str) == 0) zc_error_prev_line("IPSECKEY must specify gateway name"); if(!(name = dname_parse(parser->region, $7.str))) { zc_error_prev_line("IPSECKEY bad gateway dname %s", $7.str); break; } if($7.str[strlen($7.str)-1] != '.') { if(parser->origin == error_domain) { zc_error("cannot concatenate origin to domain name, because origin failed to parse"); break; } name = dname_concatenate(parser->rr_region, name, domain_dname(parser->origin)); } zadd_rdata_wireformat(alloc_rdata_init(parser->region, dname_name(name), name->name_size)); break; default: zc_error_prev_line("unknown IPSECKEY gateway type"); } } ; rdata_ipseckey: rdata_ipsec_base sp str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_b64(parser->region, $3.str)); /* public key */ } | rdata_ipsec_base trail ; /* RFC 6742 */ rdata_nid: STR sp dotted_str trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str)); /* NodeID */ } ; rdata_l32: STR sp dotted_str trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_wireformat(zparser_conv_a(parser->region, $3.str)); /* Locator32 */ } ; rdata_l64: STR sp dotted_str trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str)); /* Locator64 */ } ; rdata_lp: STR sp dname trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */ zadd_rdata_domain($3); /* FQDN */ } ; rdata_eui48: STR trail { zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 48)); } ; rdata_eui64: STR trail { zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 64)); } ; /* RFC7553 */ rdata_uri: STR sp STR sp dotted_str trail { zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */ zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */ zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* target */ } ; /* RFC 6844 */ rdata_caa: STR sp STR sp dotted_str trail { zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* Flags */ zadd_rdata_wireformat(zparser_conv_tag(parser->region, $3.str, $3.len)); /* Tag */ zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* Value */ } ; /* RFC7929 */ rdata_openpgpkey: str_sp_seq trail { zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str)); } ; /* RFC7477 */ rdata_csync: STR sp STR nsec_seq { zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str)); zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */ memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; } ; rdata_unknown: URR sp STR sp str_sp_seq trail { /* $2 is the number of octets, currently ignored */ $$ = zparser_conv_hex(parser->rr_region, $5.str, $5.len); } | URR sp STR trail { $$ = zparser_conv_hex(parser->rr_region, "", 0); } | URR error NL { $$ = zparser_conv_hex(parser->rr_region, "", 0); } ; %% int yywrap(void) { return 1; } /* * Create the parser. */ zparser_type * zparser_create(region_type *region, region_type *rr_region, namedb_type *db) { zparser_type *result; result = (zparser_type *) region_alloc(region, sizeof(zparser_type)); result->region = region; result->rr_region = rr_region; result->db = db; result->filename = NULL; result->current_zone = NULL; result->origin = NULL; result->prev_dname = NULL; result->default_apex = NULL; result->temporary_rdatas = (rdata_atom_type *) region_alloc_array( result->region, MAXRDATALEN, sizeof(rdata_atom_type)); return result; } /* * Initialize the parser for a new zone file. */ void zparser_init(const char *filename, uint32_t ttl, uint16_t klass, const dname_type *origin) { memset(nxtbits, 0, sizeof(nxtbits)); memset(nsecbits, 0, sizeof(nsecbits)); nsec_highest_rcode = 0; parser->default_ttl = ttl; parser->default_class = klass; parser->current_zone = NULL; parser->origin = domain_table_insert(parser->db->domains, origin); parser->prev_dname = parser->origin; parser->default_apex = parser->origin; parser->error_occurred = 0; parser->errors = 0; parser->line = 1; parser->filename = filename; parser->current_rr.rdata_count = 0; parser->current_rr.rdatas = parser->temporary_rdatas; } void yyerror(const char *message) { zc_error("%s", message); } static void error_va_list(unsigned line, const char *fmt, va_list args) { if (parser->filename) { char message[MAXSYSLOGMSGLEN]; vsnprintf(message, sizeof(message), fmt, args); log_msg(LOG_ERR, "%s:%u: %s", parser->filename, line, message); } else log_vmsg(LOG_ERR, fmt, args); ++parser->errors; parser->error_occurred = 1; } /* the line counting sux, to say the least * with this grose hack we try do give sane * numbers back */ void zc_error_prev_line(const char *fmt, ...) { va_list args; va_start(args, fmt); error_va_list(parser->line - 1, fmt, args); va_end(args); } void zc_error(const char *fmt, ...) { /* send an error message to stderr */ va_list args; va_start(args, fmt); error_va_list(parser->line, fmt, args); va_end(args); } static void warning_va_list(unsigned line, const char *fmt, va_list args) { if (parser->filename) { char m[MAXSYSLOGMSGLEN]; vsnprintf(m, sizeof(m), fmt, args); log_msg(LOG_WARNING, "%s:%u: %s", parser->filename, line, m); } else log_vmsg(LOG_WARNING, fmt, args); } void zc_warning_prev_line(const char *fmt, ...) { va_list args; va_start(args, fmt); warning_va_list(parser->line - 1, fmt, args); va_end(args); } void zc_warning(const char *fmt, ... ) { va_list args; va_start(args, fmt); warning_va_list(parser->line, fmt, args); va_end(args); } #ifdef NSEC3 static void nsec3_add_params(const char* hashalgo_str, const char* flag_str, const char* iter_str, const char* salt_str, int salt_len) { zadd_rdata_wireformat(zparser_conv_byte(parser->region, hashalgo_str)); zadd_rdata_wireformat(zparser_conv_byte(parser->region, flag_str)); zadd_rdata_wireformat(zparser_conv_short(parser->region, iter_str)); /* salt */ if(strcmp(salt_str, "-") != 0) zadd_rdata_wireformat(zparser_conv_hex_length(parser->region, salt_str, salt_len)); else zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 1)); } #endif /* NSEC3 */ nsd-4.1.26/ipc.c0000664000175000017500000005411313374540300012750 0ustar wouterwouter/* * ipc.c - Interprocess communication routines. Handlers read and write. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "ipc.h" #include "buffer.h" #include "xfrd-tcp.h" #include "nsd.h" #include "namedb.h" #include "xfrd.h" #include "xfrd-notify.h" #include "difffile.h" #include "rrl.h" /* attempt to send NSD_STATS command to child fd */ static void send_stat_to_child(struct main_ipc_handler_data* data, int fd); /* send reload request over the IPC channel */ static void xfrd_send_reload_req(xfrd_state_type* xfrd); /* send quit request over the IPC channel */ static void xfrd_send_quit_req(xfrd_state_type* xfrd); /* perform read part of handle ipc for xfrd */ static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd); static void ipc_child_quit(struct nsd* nsd) ATTR_NORETURN; static void ipc_child_quit(struct nsd* nsd) { /* call shutdown and quit routines */ nsd->mode = NSD_QUIT; #ifdef BIND8_STATS bind8_stats(nsd); #endif /* BIND8_STATS */ #ifdef MEMCLEAN /* OS collects memory pages */ #ifdef RATELIMIT rrl_deinit(nsd->this_child->child_num); #endif event_base_free(nsd->event_base); region_destroy(nsd->server_region); #endif server_shutdown(nsd); exit(0); } void child_handle_parent_command(int fd, short event, void* arg) { sig_atomic_t mode; int len; struct ipc_handler_conn_data *data = (struct ipc_handler_conn_data *) arg; if (!(event & EV_READ)) { return; } if ((len = read(fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_parent_command: read: %s", strerror(errno)); return; } if (len == 0) { /* parent closed the connection. Quit */ ipc_child_quit(data->nsd); return; } switch (mode) { case NSD_STATS: data->nsd->mode = mode; break; case NSD_QUIT: ipc_child_quit(data->nsd); break; case NSD_QUIT_CHILD: /* close our listening sockets and ack */ server_close_all_sockets(data->nsd->udp, data->nsd->ifs); server_close_all_sockets(data->nsd->tcp, data->nsd->ifs); /* mode == NSD_QUIT_CHILD */ if(write(fd, &mode, sizeof(mode)) == -1) { VERBOSITY(3, (LOG_INFO, "quit child write: %s", strerror(errno))); } ipc_child_quit(data->nsd); break; case NSD_QUIT_WITH_STATS: #ifdef BIND8_STATS DEBUG(DEBUG_IPC, 2, (LOG_INFO, "quit QUIT_WITH_STATS")); /* reply with ack and stats and then quit */ if(!write_socket(fd, &mode, sizeof(mode))) { log_msg(LOG_ERR, "cannot write quitwst to parent"); } if(!write_socket(fd, &data->nsd->st, sizeof(data->nsd->st))) { log_msg(LOG_ERR, "cannot write stats to parent"); } fsync(fd); #endif /* BIND8_STATS */ ipc_child_quit(data->nsd); break; default: log_msg(LOG_ERR, "handle_parent_command: bad mode %d", (int) mode); break; } } void parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; struct ipc_handler_conn_data *data = (struct ipc_handler_conn_data *) handler->user_data; if (!(event_types & NETIO_EVENT_READ)) { return; } if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_xfrd_command: read: %s", strerror(errno)); return; } if (len == 0) { /* xfrd closed, we must quit */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "handle_xfrd_command: xfrd closed channel.")); close(handler->fd); handler->fd = -1; data->nsd->mode = NSD_SHUTDOWN; return; } switch (mode) { case NSD_RELOAD: DEBUG(DEBUG_IPC,1, (LOG_INFO, "parent handle xfrd command RELOAD")); data->nsd->signal_hint_reload = 1; break; case NSD_QUIT: case NSD_SHUTDOWN: data->nsd->mode = mode; break; case NSD_STATS: data->nsd->signal_hint_stats = 1; break; case NSD_REAP_CHILDREN: data->nsd->signal_hint_child = 1; break; default: log_msg(LOG_ERR, "handle_xfrd_command: bad mode %d", (int) mode); break; } } static void send_stat_to_child(struct main_ipc_handler_data* data, int fd) { sig_atomic_t cmd = NSD_STATS; if(write(fd, &cmd, sizeof(cmd)) == -1) { if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "svrmain: problems sending stats to child %d command: %s", (int)data->child->pid, strerror(errno)); return; } data->child->need_to_send_STATS = 0; } #ifndef NDEBUG int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass); static void debug_print_fwd_name(int ATTR_UNUSED(len), buffer_type* packet, int acl_num) { uint8_t qnamebuf[MAXDOMAINLEN]; uint16_t qtype, qclass; const dname_type* dname; region_type* tempregion = region_create(xalloc, free); size_t bufpos = buffer_position(packet); buffer_rewind(packet); buffer_skip(packet, 12); if(packet_read_query_section(packet, qnamebuf, &qtype, &qclass)) { dname = dname_make(tempregion, qnamebuf, 1); log_msg(LOG_INFO, "main: fwd packet for %s, acl %d", dname_to_string(dname,0), acl_num); } else { log_msg(LOG_INFO, "main: fwd packet badqname, acl %d", acl_num); } buffer_set_position(packet, bufpos); region_destroy(tempregion); } #endif static void send_quit_to_child(struct main_ipc_handler_data* data, int fd) { #ifdef BIND8_STATS sig_atomic_t cmd = NSD_QUIT_WITH_STATS; #else sig_atomic_t cmd = NSD_QUIT; #endif if(write(fd, &cmd, sizeof(cmd)) == -1) { if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "svrmain: problems sending quit to child %d command: %s", (int)data->child->pid, strerror(errno)); return; } data->child->need_to_send_QUIT = 0; DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: sent quit to child %d", (int)data->child->pid)); } /** the child is done, mark it as exited */ static void child_is_done(struct nsd* nsd, int fd) { size_t i; if(fd != -1) close(fd); for(i=0; ichild_count; ++i) if(nsd->children[i].child_fd == fd) { nsd->children[i].child_fd = -1; nsd->children[i].handler->fd = -1; if(nsd->children[i].need_to_exit) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "server %d is done", (int)nsd->children[i].pid)); nsd->children[i].has_exited = 1; } else { log_msg(LOG_WARNING, "server %d died unexpectedly, restarting", (int)nsd->children[i].pid); /* this child is now going to be re-forked as * a subprocess of this server-main, and if a * reload is in progress the other children * are subprocesses of reload. Until the * reload is done and they are all reforked. */ nsd->children[i].pid = -1; nsd->restart_children = 1; } } parent_check_all_children_exited(nsd); } #ifdef BIND8_STATS /** add stats to total */ void stats_add(struct nsdst* total, struct nsdst* s) { unsigned i; for(i=0; iqtype)/sizeof(stc_type); i++) total->qtype[i] += s->qtype[i]; for(i=0; iqclass)/sizeof(stc_type); i++) total->qclass[i] += s->qclass[i]; total->qudp += s->qudp; total->qudp6 += s->qudp6; total->ctcp += s->ctcp; total->ctcp6 += s->ctcp6; for(i=0; ircode)/sizeof(stc_type); i++) total->rcode[i] += s->rcode[i]; for(i=0; iopcode)/sizeof(stc_type); i++) total->opcode[i] += s->opcode[i]; total->dropped += s->dropped; total->truncated += s->truncated; total->wrongzone += s->wrongzone; total->txerr += s->txerr; total->rxerr += s->rxerr; total->edns += s->edns; total->ednserr += s->ednserr; total->raxfr += s->raxfr; total->nona += s->nona; total->db_disk = s->db_disk; total->db_mem = s->db_mem; } /** subtract stats from total */ void stats_subtract(struct nsdst* total, struct nsdst* s) { unsigned i; for(i=0; iqtype)/sizeof(stc_type); i++) total->qtype[i] -= s->qtype[i]; for(i=0; iqclass)/sizeof(stc_type); i++) total->qclass[i] -= s->qclass[i]; total->qudp -= s->qudp; total->qudp6 -= s->qudp6; total->ctcp -= s->ctcp; total->ctcp6 -= s->ctcp6; for(i=0; ircode)/sizeof(stc_type); i++) total->rcode[i] -= s->rcode[i]; for(i=0; iopcode)/sizeof(stc_type); i++) total->opcode[i] -= s->opcode[i]; total->dropped -= s->dropped; total->truncated -= s->truncated; total->wrongzone -= s->wrongzone; total->txerr -= s->txerr; total->rxerr -= s->rxerr; total->edns -= s->edns; total->ednserr -= s->ednserr; total->raxfr -= s->raxfr; total->nona -= s->nona; } #define FINAL_STATS_TIMEOUT 10 /* seconds */ static void read_child_stats(struct nsd* nsd, struct nsd_child* child, int fd) { struct nsdst s; errno=0; if(block_read(nsd, fd, &s, sizeof(s), FINAL_STATS_TIMEOUT)!=sizeof(s)) { log_msg(LOG_ERR, "problems reading finalstats from server " "%d: %s", (int)child->pid, strerror(errno)); } else { stats_add(&nsd->st, &s); child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6; /* we know that the child is going to close the connection * now (this is an ACK of the QUIT_W_STATS so we know the * child is done, no longer sending e.g. NOTIFY contents) */ child_is_done(nsd, fd); } } #endif /* BIND8_STATS */ void parent_handle_child_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; struct main_ipc_handler_data *data = (struct main_ipc_handler_data*)handler->user_data; /* do a nonblocking write to the child if it is ready. */ if (event_types & NETIO_EVENT_WRITE) { if(data->child->need_to_send_STATS && !data->child->need_to_exit) { send_stat_to_child(data, handler->fd); } else if(data->child->need_to_send_QUIT) { send_quit_to_child(data, handler->fd); if(!data->child->need_to_send_QUIT) handler->event_types = NETIO_EVENT_READ; } else { handler->event_types = NETIO_EVENT_READ; } } if (!(event_types & NETIO_EVENT_READ)) { return; } if (data->forward_mode) { int got_acl; /* forward the data to xfrd */ DEBUG(DEBUG_IPC,2, (LOG_INFO, "main passed packet readup %d", (int)data->got_bytes)); if(data->got_bytes < sizeof(data->total_bytes)) { if ((len = read(handler->fd, (char*)&data->total_bytes+data->got_bytes, sizeof(data->total_bytes)-data->got_bytes)) == -1) { log_msg(LOG_ERR, "handle_child_command: read: %s", strerror(errno)); return; } if(len == 0) { /* EOF */ data->forward_mode = 0; return; } data->got_bytes += len; if(data->got_bytes < sizeof(data->total_bytes)) return; data->total_bytes = ntohs(data->total_bytes); buffer_clear(data->packet); if(data->total_bytes > buffer_capacity(data->packet)) { log_msg(LOG_ERR, "internal error: ipc too large"); exit(1); } return; } /* read the packet */ if(data->got_bytes-sizeof(data->total_bytes) < data->total_bytes) { if((len = read(handler->fd, buffer_current(data->packet), data->total_bytes - (data->got_bytes-sizeof(data->total_bytes)) )) == -1 ) { log_msg(LOG_ERR, "handle_child_command: read: %s", strerror(errno)); return; } if(len == 0) { /* EOF */ data->forward_mode = 0; return; } data->got_bytes += len; buffer_skip(data->packet, len); /* read rest later */ return; } /* read the acl numbers */ got_acl = data->got_bytes - sizeof(data->total_bytes) - data->total_bytes; if((len = read(handler->fd, (char*)&data->acl_num+got_acl, sizeof(data->acl_num)+sizeof(data->acl_xfr)-got_acl)) == -1 ) { log_msg(LOG_ERR, "handle_child_command: read: %s", strerror(errno)); return; } if(len == 0) { /* EOF */ data->forward_mode = 0; return; } got_acl += len; data->got_bytes += len; if(got_acl >= (int)(sizeof(data->acl_num)+sizeof(data->acl_xfr))) { uint16_t len = htons(data->total_bytes); DEBUG(DEBUG_IPC,2, (LOG_INFO, "main fwd passed packet write %d", (int)data->got_bytes)); #ifndef NDEBUG if(nsd_debug_level >= 2) debug_print_fwd_name(len, data->packet, data->acl_num); #endif data->forward_mode = 0; mode = NSD_PASS_TO_XFRD; if(!write_socket(*data->xfrd_sock, &mode, sizeof(mode)) || !write_socket(*data->xfrd_sock, &len, sizeof(len)) || !write_socket(*data->xfrd_sock, buffer_begin(data->packet), data->total_bytes) || !write_socket(*data->xfrd_sock, &data->acl_num, sizeof(data->acl_num)) || !write_socket(*data->xfrd_sock, &data->acl_xfr, sizeof(data->acl_xfr))) { log_msg(LOG_ERR, "error in ipc fwd main2xfrd: %s", strerror(errno)); } } return; } /* read command from ipc */ if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_child_command: read: %s", strerror(errno)); return; } if (len == 0) { child_is_done(data->nsd, handler->fd); return; } switch (mode) { case NSD_QUIT: data->nsd->mode = mode; break; #ifdef BIND8_STATS case NSD_QUIT_WITH_STATS: read_child_stats(data->nsd, data->child, handler->fd); break; #endif /* BIND8_STATS */ case NSD_STATS: data->nsd->signal_hint_stats = 1; break; case NSD_REAP_CHILDREN: data->nsd->signal_hint_child = 1; break; case NSD_PASS_TO_XFRD: /* set mode for handle_child_command; echo to xfrd. */ data->forward_mode = 1; data->got_bytes = 0; data->total_bytes = 0; break; default: log_msg(LOG_ERR, "handle_child_command: bad mode %d", (int) mode); break; } } void parent_check_all_children_exited(struct nsd* nsd) { size_t i; for(i=0; i < nsd->child_count; i++) { if(!nsd->children[i].need_to_exit) return; if(!nsd->children[i].has_exited) return; } nsd->mode = NSD_QUIT_SYNC; DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: all children exited. quit sync.")); } void parent_handle_reload_command(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { sig_atomic_t mode; int len; size_t i; struct nsd *nsd = (struct nsd*) handler->user_data; if (!(event_types & NETIO_EVENT_READ)) { return; } /* read command from ipc */ if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) { log_msg(LOG_ERR, "handle_reload_command: read: %s", strerror(errno)); return; } if (len == 0) { if(handler->fd != -1) { close(handler->fd); handler->fd = -1; } log_msg(LOG_ERR, "handle_reload_cmd: reload closed cmd channel"); nsd->reload_failed = 1; return; } switch (mode) { case NSD_QUIT_SYNC: /* set all children to exit, only then notify xfrd. */ /* so that buffered packets to pass to xfrd can arrive. */ for(i=0; i < nsd->child_count; i++) { nsd->children[i].need_to_exit = 1; if(nsd->children[i].pid > 0 && nsd->children[i].child_fd != -1) { nsd->children[i].need_to_send_QUIT = 1; nsd->children[i].handler->event_types |= NETIO_EVENT_WRITE; } else { if(nsd->children[i].child_fd == -1) nsd->children[i].has_exited = 1; } } parent_check_all_children_exited(nsd); break; default: log_msg(LOG_ERR, "handle_reload_command: bad mode %d", (int) mode); break; } } static void xfrd_send_reload_req(xfrd_state_type* xfrd) { sig_atomic_t req = NSD_RELOAD; uint64_t p = xfrd->last_task->data; udb_ptr_unlink(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); task_process_sync(xfrd->nsd->task[xfrd->nsd->mytask]); /* ask server_main for a reload */ if(write(xfrd->ipc_handler.ev_fd, &req, sizeof(req)) == -1) { udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); udb_ptr_set(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask], p); if(errno == EAGAIN || errno == EINTR) return; /* try again later */ log_msg(LOG_ERR, "xfrd: problems sending reload command: %s", strerror(errno)); return; } DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: asked nsd to reload new updates")); /* swapped task to other side, start to use other task udb. */ xfrd->nsd->mytask = 1 - xfrd->nsd->mytask; task_remap(xfrd->nsd->task[xfrd->nsd->mytask]); udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]); assert(udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0); xfrd_prepare_zones_for_reload(); xfrd->reload_cmd_last_sent = xfrd_time(); xfrd->need_to_send_reload = 0; xfrd->can_send_reload = 0; } void ipc_xfrd_set_listening(struct xfrd_state* xfrd, short mode) { int fd = xfrd->ipc_handler.ev_fd; struct event_base* base = xfrd->event_base; event_del(&xfrd->ipc_handler); event_set(&xfrd->ipc_handler, fd, mode, xfrd_handle_ipc, xfrd); if(event_base_set(base, &xfrd->ipc_handler) != 0) log_msg(LOG_ERR, "ipc: cannot set event_base"); /* no timeout for IPC events */ if(event_add(&xfrd->ipc_handler, NULL) != 0) log_msg(LOG_ERR, "ipc: cannot add event"); xfrd->ipc_handler_flags = mode; } static void xfrd_send_shutdown_req(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_SHUTDOWN; xfrd->ipc_send_blocked = 1; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send shutdown")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing shutdown to main: %s", strerror(errno)); } xfrd->need_to_send_shutdown = 0; } static void xfrd_send_quit_req(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_QUIT; xfrd->ipc_send_blocked = 1; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send ackreload(quit)")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing ack to main: %s", strerror(errno)); } xfrd->need_to_send_quit = 0; } static void xfrd_send_stats(xfrd_state_type* xfrd) { sig_atomic_t cmd = NSD_STATS; DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send stats")); if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "xfrd: error writing stats to main: %s", strerror(errno)); } xfrd->need_to_send_stats = 0; } void xfrd_handle_ipc(int ATTR_UNUSED(fd), short event, void* arg) { xfrd_state_type* xfrd = (xfrd_state_type*)arg; if ((event & EV_READ)) { /* first attempt to read as a signal from main * could block further send operations */ xfrd_handle_ipc_read(&xfrd->ipc_handler, xfrd); } if ((event & EV_WRITE)) { if(xfrd->ipc_send_blocked) { /* wait for RELOAD_DONE */ ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); return; } if(xfrd->need_to_send_shutdown) { xfrd_send_shutdown_req(xfrd); } else if(xfrd->need_to_send_quit) { xfrd_send_quit_req(xfrd); } else if(xfrd->can_send_reload && xfrd->need_to_send_reload) { xfrd_send_reload_req(xfrd); } else if(xfrd->need_to_send_stats) { xfrd_send_stats(xfrd); } if(!(xfrd->can_send_reload && xfrd->need_to_send_reload) && !xfrd->need_to_send_shutdown && !xfrd->need_to_send_quit && !xfrd->need_to_send_stats) { /* disable writing for now */ ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ); } } } static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd) { sig_atomic_t cmd; int len; if(xfrd->ipc_conn->is_reading==2) { buffer_type* tmp = xfrd->ipc_pass; uint32_t acl_num; int32_t acl_xfr; /* read acl_num */ int ret = conn_read(xfrd->ipc_conn); if(ret == -1) { log_msg(LOG_ERR, "xfrd: error in read ipc: %s", strerror(errno)); xfrd->ipc_conn->is_reading = 0; return; } if(ret == 0) return; buffer_flip(xfrd->ipc_conn->packet); xfrd->ipc_pass = xfrd->ipc_conn->packet; xfrd->ipc_conn->packet = tmp; xfrd->ipc_conn->is_reading = 0; acl_num = buffer_read_u32(xfrd->ipc_pass); acl_xfr = (int32_t)buffer_read_u32(xfrd->ipc_pass); xfrd_handle_passed_packet(xfrd->ipc_conn->packet, acl_num, acl_xfr); return; } if(xfrd->ipc_conn->is_reading) { /* reading an IPC message */ buffer_type* tmp; int ret = conn_read(xfrd->ipc_conn); if(ret == -1) { log_msg(LOG_ERR, "xfrd: error in read ipc: %s", strerror(errno)); xfrd->ipc_conn->is_reading = 0; return; } if(ret == 0) return; buffer_flip(xfrd->ipc_conn->packet); /* use ipc_conn to read remaining data as well */ tmp = xfrd->ipc_pass; xfrd->ipc_conn->is_reading=2; xfrd->ipc_pass = xfrd->ipc_conn->packet; xfrd->ipc_conn->packet = tmp; xfrd->ipc_conn->total_bytes = sizeof(xfrd->ipc_conn->msglen); xfrd->ipc_conn->msglen = 2*sizeof(uint32_t); buffer_clear(xfrd->ipc_conn->packet); buffer_set_limit(xfrd->ipc_conn->packet, xfrd->ipc_conn->msglen); return; } if((len = read(handler->ev_fd, &cmd, sizeof(cmd))) == -1) { if(errno != EINTR && errno != EAGAIN) log_msg(LOG_ERR, "xfrd_handle_ipc: read: %s", strerror(errno)); return; } if(len == 0) { /* parent closed the connection. Quit */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main closed connection.")); xfrd->shutdown = 1; return; } switch(cmd) { case NSD_QUIT: case NSD_SHUTDOWN: DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main sent shutdown cmd.")); xfrd->shutdown = 1; break; case NSD_RELOAD_DONE: /* reload has finished */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_DONE")); if(block_read(NULL, handler->ev_fd, &xfrd->reload_pid, sizeof(pid_t), -1) != sizeof(pid_t)) { log_msg(LOG_ERR, "xfrd cannot get reload_pid"); } /* read the not-mytask for the results and soainfo */ xfrd_process_task_result(xfrd, xfrd->nsd->task[1-xfrd->nsd->mytask]); /* reset the IPC, (and the nonblocking ipc write; the new parent does not want half a packet) */ xfrd->can_send_reload = 1; xfrd->ipc_send_blocked = 0; ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); xfrd_reopen_logfile(); xfrd_check_failed_updates(); break; case NSD_PASS_TO_XFRD: DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv PASS_TO_XFRD")); xfrd->ipc_conn->is_reading = 1; break; case NSD_RELOAD_REQ: DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_REQ")); /* make reload happen, right away, and schedule file check */ task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, NULL); xfrd_set_reload_now(xfrd); break; case NSD_RELOAD: /* main tells us that reload is done, stop ipc send to main */ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD")); ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); xfrd->need_to_send_quit = 1; break; default: log_msg(LOG_ERR, "xfrd_handle_ipc: bad mode %d (%d)", (int)cmd, (int)ntohl(cmd)); break; } if(xfrd->ipc_conn->is_reading) { /* setup read of info */ xfrd->ipc_conn->total_bytes = 0; xfrd->ipc_conn->msglen = 0; buffer_clear(xfrd->ipc_conn->packet); } } nsd-4.1.26/xfrd-notify.c0000664000175000017500000003771513212010210014436 0ustar wouterwouter/* * xfrd-notify.c - notify sending routines * * Copyright (c) 2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include "xfrd-notify.h" #include "xfrd.h" #include "xfrd-tcp.h" #include "packet.h" #define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */ /* start sending notifies */ static void notify_enable(struct notify_zone* zone, struct xfrd_soa* new_soa); /* setup the notify active state */ static void setup_notify_active(struct notify_zone* zone); /* handle zone notify send */ static void xfrd_handle_notify_send(int fd, short event, void* arg); static int xfrd_notify_send_udp(struct notify_zone* zone, int index); static void notify_send_disable(struct notify_zone* zone) { zone->notify_send_enable = 0; 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; } } void notify_disable(struct notify_zone* zone) { zone->notify_current = 0; /* if added, then remove */ 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 */ while(xfrd->notify_waiting_first) { /* snip off */ struct notify_zone* wz = xfrd->notify_waiting_first; assert(wz->is_waiting); wz->is_waiting = 0; xfrd->notify_waiting_first = wz->waiting_next; if(wz->waiting_next) wz->waiting_next->waiting_prev = NULL; if(xfrd->notify_waiting_last == wz) xfrd->notify_waiting_last = NULL; /* see if this zone needs notify sending */ if(wz->notify_current) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify off waiting list.", zone->apex_str) ); setup_notify_active(wz); return; } } } xfrd->notify_udp_num--; } void init_notify_send(rbtree_type* tree, region_type* region, struct zone_options* options) { struct notify_zone* not = (struct notify_zone*) region_alloc(region, sizeof(struct notify_zone)); memset(not, 0, sizeof(struct notify_zone)); not->apex = options->node.key; not->apex_str = options->name; not->node.key = not->apex; not->options = options; /* if master zone and have a SOA */ not->current_soa = (struct xfrd_soa*)region_alloc(region, sizeof(struct xfrd_soa)); memset(not->current_soa, 0, sizeof(struct xfrd_soa)); not->notify_send_handler.ev_fd = -1; not->notify_send6_handler.ev_fd = -1; not->is_waiting = 0; not->notify_send_enable = 0; not->notify_send6_enable = 0; tsig_create_record_custom(¬->notify_tsig, NULL, 0, 0, 4); not->notify_current = 0; rbtree_insert(tree, (rbnode_type*)not); } void xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname) { /* find it */ struct notify_zone* not = (struct notify_zone*)rbtree_delete( xfrd->notify_zones, dname); if(!not) return; /* waiting list */ if(not->is_waiting) { if(not->waiting_prev) not->waiting_prev->waiting_next = not->waiting_next; else xfrd->notify_waiting_first = not->waiting_next; if(not->waiting_next) not->waiting_next->waiting_prev = not->waiting_prev; else xfrd->notify_waiting_last = not->waiting_prev; not->is_waiting = 0; } /* event */ if(not->notify_send_enable || not->notify_send6_enable) { notify_disable(not); } /* del tsig */ tsig_delete_record(¬->notify_tsig, NULL); /* free it */ region_recycle(xfrd->region, not->current_soa, sizeof(xfrd_soa_type)); /* the apex is recycled when the zone_options.node.key is removed */ region_recycle(xfrd->region, not, sizeof(*not)); } static int 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 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->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->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->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 notify_pkt_done(struct notify_zone* zone, int index) { 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_handle_notify_reply(struct notify_zone* zone, buffer_type* packet, struct sockaddr* src, socklen_t srclen) { int i; for(i=0; ipkts[i].dest) continue; /* based on destination */ if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest)) continue; if(reply_pkt_is_ack(zone, packet, i)) { /* is done */ notify_pkt_done(zone, i); return; } else { /* retry */ notify_pkt_retry(zone, i); return; } } } 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->pkts[index].notify_query_id = ID(packet); OPCODE_SET(packet, OPCODE_NOTIFY); AA_SET(packet); if(zone->current_soa->serial != 0) { /* add current SOA to answer section */ ANCOUNT_SET(packet, 1); xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa); } if(zone->pkts[index].dest->key_options) { xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest); } buffer_flip(packet); if((zone->pkts[index].dest->is_ipv6 && zone->notify_send6_handler.ev_fd == -1) || (!zone->pkts[index].dest->is_ipv6 && zone->notify_send_handler.ev_fd == -1)) { /* open fd */ int fd = xfrd_send_udp(zone->pkts[index].dest, packet, zone->options->pattern->outgoing_interface); if(fd == -1) { log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s", zone->apex_str, zone->pkts[index].notify_retry, zone->pkts[index].dest->ip_address_spec); return 0; } if(zone->pkts[index].dest->is_ipv6) zone->notify_send6_handler.ev_fd = fd; else zone->notify_send_handler.ev_fd = fd; } else { /* send on existing fd */ #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif /* INET6 */ int fd; socklen_t to_len = xfrd_acl_sockaddr_to( zone->pkts[index].dest, &to); if(zone->pkts[index].dest->is_ipv6) fd = zone->notify_send6_handler.ev_fd; else fd = zone->notify_send_handler.ev_fd; if(sendto(fd, buffer_current(packet), buffer_remaining(packet), 0, (struct sockaddr*)&to, to_len) == -1) { log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s", zone->pkts[index].dest->ip_address_spec, strerror(errno)); return 0; } } zone->pkts[index].send_time = time(NULL); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s", zone->apex_str, zone->pkts[index].notify_retry, zone->pkts[index].dest->ip_address_spec)); return 1; } static void notify_timeout_check(struct notify_zone* zone) { time_t now = time(NULL); int i; for(i=0; ipkts[i].dest) continue; if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) { notify_pkt_retry(zone, i); } } } static void notify_start_pkts(struct notify_zone* zone) { int i; if(!zone->notify_current) return; /* no more acl to send to */ for(i=0; ipkts[i].dest==NULL && zone->notify_current) { zone->pkts[i].dest = zone->notify_current; zone->notify_current = zone->notify_current->next; zone->pkts[i].notify_retry = 0; zone->pkts[i].notify_query_id = 0; zone->pkts[i].send_time = 0; zone->notify_pkt_count++; if(!xfrd_notify_send_udp(zone, i)) { notify_pkt_retry(zone, i); } } } } static void notify_setup_event(struct notify_zone* zone) { if(zone->notify_send_handler.ev_fd != -1) { int fd = zone->notify_send_handler.ev_fd; if(zone->notify_send_enable) { event_del(&zone->notify_send_handler); } zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT; event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notify_send: event_base_set failed"); if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notify_send: event_add failed"); zone->notify_send_enable = 1; } 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 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(); 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, (struct sockaddr*)&src, &srclen)) { /* find entry, send retry or make entry NULL */ xfrd_handle_notify_reply(zone, packet, (struct sockaddr*)&src, srclen); } } if((event & EV_TIMEOUT)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout", zone->apex_str)); /* timeout, try again */ } /* 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_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; if(zone->notify_send_enable) notify_send_disable(zone); event_set(&zone->notify_send_handler, -1, EV_TIMEOUT, xfrd_handle_notify_send, zone); if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0) log_msg(LOG_ERR, "notifysend: event_base_set failed"); if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0) log_msg(LOG_ERR, "notifysend: evtimer_add failed"); zone->notify_send_enable = 1; } static void notify_enable(struct notify_zone* zone, struct xfrd_soa* new_soa) { if(!zone->options->pattern->notify) { return; /* no notify acl, nothing to do */ } if(new_soa == NULL) memset(zone->current_soa, 0, sizeof(xfrd_soa_type)); else memcpy(zone->current_soa, new_soa, sizeof(xfrd_soa_type)); if(zone->is_waiting) return; if(xfrd->notify_udp_num < XFRD_MAX_UDP_NOTIFY) { setup_notify_active(zone); xfrd->notify_udp_num++; return; } /* put it in waiting list */ zone->notify_current = zone->options->pattern->notify; zone->is_waiting = 1; zone->waiting_next = NULL; zone->waiting_prev = xfrd->notify_waiting_last; if(xfrd->notify_waiting_last) { xfrd->notify_waiting_last->waiting_next = zone; } else { xfrd->notify_waiting_first = zone; } xfrd->notify_waiting_last = zone; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify on waiting list.", zone->apex_str)); } void xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd) { xfrd_zone_type* xz; 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) notify_enable(zone, &xz->soa_nsd); else notify_enable(zone, NULL); } void xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa) { /* lookup the zone */ struct notify_zone* zone = (struct notify_zone*) rbtree_search(tree, apex); assert(zone); if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); } void notify_handle_master_zone_soainfo(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new_soa) { /* lookup the zone */ struct notify_zone* zone = (struct notify_zone*) rbtree_search(tree, apex); if(!zone) return; /* got SOAINFO but zone was deleted meanwhile */ /* check if SOA changed */ if( (new_soa == NULL && zone->current_soa->serial == 0) || (new_soa && new_soa->serial == zone->current_soa->serial)) return; if(zone->notify_send_enable || zone->notify_send6_enable) notify_disable(zone); notify_enable(zone, new_soa); } void close_notify_fds(rbtree_type* tree) { struct notify_zone* zone; RBTREE_FOR(zone, struct notify_zone*, tree) { if(zone->notify_send_enable || zone->notify_send6_enable) notify_send_disable(zone); } } nsd-4.1.26/dnstap/0000775000175000017500000000000013401455020013311 5ustar wouterwouternsd-4.1.26/dnstap/dnstap.h0000664000175000017500000001127113355426313014770 0ustar wouterwouter/* dnstap support for NSD */ /* * Copyright (c) 2013-2014, Farsight Security, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef NSD_DNSTAP_H #define NSD_DNSTAP_H #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP struct nsd_options; struct fstrm_io; struct fstrm_queue; struct dt_env { /** dnstap I/O thread */ struct fstrm_iothr *iothr; /** dnstap I/O thread input queue */ struct fstrm_iothr_queue *ioq; /** dnstap "identity" field, NULL if disabled */ char *identity; /** dnstap "version" field, NULL if disabled */ char *version; /** length of "identity" field */ unsigned len_identity; /** length of "version" field */ unsigned len_version; /** whether to log Message/AUTH_QUERY */ unsigned log_auth_query_messages : 1; /** whether to log Message/AUTH_RESPONSE */ unsigned log_auth_response_messages : 1; }; /** * Create dnstap environment object. Afterwards, call dt_apply_cfg() to fill in * the config variables and dt_init() to fill in the per-worker state. Each * worker needs a copy of this object but with its own I/O queue (the fq field * of the structure) to ensure lock-free access to its own per-worker circular * queue. Duplicate the environment object if more than one worker needs to * share access to the dnstap I/O socket. * @param socket_path: path to dnstap logging socket, must be non-NULL. * @param num_workers: number of worker threads, must be > 0. * @return dt_env object, NULL on failure. */ struct dt_env * dt_create(const char *socket_path, unsigned num_workers); /** * Apply config settings. * @param env: dnstap environment object. * @param cfg: new config settings. */ void dt_apply_cfg(struct dt_env *env, struct nsd_options *cfg); /** * Initialize per-worker state in dnstap environment object. * @param env: dnstap environment object to initialize, created with dt_create(). * @return: true on success, false on failure. */ int dt_init(struct dt_env *env); /** * Delete dnstap environment object. Closes dnstap I/O socket and deletes all * per-worker I/O queues. */ void dt_delete(struct dt_env *env); /** * Create and send a new dnstap "Message" event of type AUTH_QUERY. * @param env: dnstap environment object. * @param addr: address/port of client. * @param is_tcp: true for tcp, false for udp. * @param zone: zone name, or NULL. in wireformat. * @param zonelen: length of zone in bytes. * @param pkt: query message. * @param pktlen: length of pkt. */ void dt_msg_send_auth_query(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen); /** * Create and send a new dnstap "Message" event of type AUTH_RESPONSE. * @param env: dnstap environment object. * @param addr: address/port of client. * @param is_tcp: true for tcp, false for udp. * @param zone: zone name, or NULL. in wireformat. * @param zonelen: length of zone in bytes. * @param pkt: response message. * @param pktlen: length of pkt. */ void dt_msg_send_auth_response(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen); #endif /* USE_DNSTAP */ #endif /* NSD_DNSTAP_H */ nsd-4.1.26/dnstap/dnstap_config.h.in0000664000175000017500000000060213355344112016712 0ustar wouterwouter#ifndef UNBOUND_DNSTAP_CONFIG_H #define UNBOUND_DNSTAP_CONFIG_H /* * Process this file (dnstap_config.h.in) with AC_CONFIG_FILES to generate * dnstap_config.h. * * This file exists so that USE_DNSTAP can be used without including config.h. */ #if @ENABLE_DNSTAP@ /* ENABLE_DNSTAP */ # ifndef USE_DNSTAP # define USE_DNSTAP 1 # endif #endif #endif /* UNBOUND_DNSTAP_CONFIG_H */ nsd-4.1.26/dnstap/dnstap_collector.c0000664000175000017500000003501413364352613017033 0ustar wouterwouter/* * dnstap/dnstap_collector.c -- nsd collector process for dnstap information * * Copyright (c) 2018, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #ifndef USE_MINI_EVENT # ifdef HAVE_EVENT_H # include # else # include # include "event2/event_struct.h" # include "event2/event_compat.h" # endif #else # include "mini_event.h" #endif #include "dnstap/dnstap_collector.h" #include "dnstap/dnstap.h" #include "util.h" #include "nsd.h" #include "region-allocator.h" #include "buffer.h" #include "namedb.h" #include "options.h" struct dt_collector* dt_collector_create(struct nsd* nsd) { int i, sv[2]; struct dt_collector* dt_col = (struct dt_collector*)xalloc_zero( sizeof(*dt_col)); dt_col->count = nsd->child_count; dt_col->dt_env = NULL; dt_col->region = region_create(xalloc, free); dt_col->send_buffer = buffer_create(dt_col->region, /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + addr */ 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 + #ifdef INET6 sizeof(struct sockaddr_storage) #else sizeof(struct sockaddr_in) #endif ); /* open pipes in struct nsd */ nsd->dt_collector_fd_send = (int*)xalloc_array_zero(dt_col->count, sizeof(int)); nsd->dt_collector_fd_recv = (int*)xalloc_array_zero(dt_col->count, sizeof(int)); for(i=0; icount; i++) { int fd[2]; fd[0] = -1; fd[1] = -1; if(pipe(fd) < 0) { error("dnstap_collector: cannot create pipe: %s", strerror(errno)); } if(fcntl(fd[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } if(fcntl(fd[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } nsd->dt_collector_fd_recv[i] = fd[0]; nsd->dt_collector_fd_send[i] = fd[1]; } /* open socketpair */ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { error("dnstap_collector: cannot create socketpair: %s", strerror(errno)); } if(fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } if(fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno)); } dt_col->cmd_socket_dt = sv[0]; dt_col->cmd_socket_nsd = sv[1]; return dt_col; } void dt_collector_destroy(struct dt_collector* dt_col, struct nsd* nsd) { if(!dt_col) return; free(nsd->dt_collector_fd_recv); nsd->dt_collector_fd_recv = NULL; free(nsd->dt_collector_fd_send); nsd->dt_collector_fd_send = NULL; region_destroy(dt_col->region); free(dt_col); } void dt_collector_close(struct dt_collector* dt_col, struct nsd* nsd) { int i; if(!dt_col) return; if(dt_col->cmd_socket_dt != -1) { close(dt_col->cmd_socket_dt); dt_col->cmd_socket_dt = -1; } if(dt_col->cmd_socket_nsd != -1) { close(dt_col->cmd_socket_nsd); dt_col->cmd_socket_nsd = -1; } for(i=0; icount; i++) { if(nsd->dt_collector_fd_recv[i] != -1) { close(nsd->dt_collector_fd_recv[i]); nsd->dt_collector_fd_recv[i] = -1; } if(nsd->dt_collector_fd_send[i] != -1) { close(nsd->dt_collector_fd_send[i]); nsd->dt_collector_fd_send[i] = -1; } } } /* handle command from nsd to dt collector. * mostly, check for fd closed, this means we have to exit */ void dt_handle_cmd_from_nsd(int ATTR_UNUSED(fd), short event, void* arg) { struct dt_collector* dt_col = (struct dt_collector*)arg; if((event&EV_READ) != 0) { event_base_loopexit(dt_col->event_base, NULL); } } /* read data from fd into buffer, true when message is complete */ static int read_into_buffer(int fd, struct buffer* buf) { size_t msglen; ssize_t r; if(buffer_position(buf) < 4) { /* read the length of the message */ r = read(fd, buffer_current(buf), 4 - buffer_position(buf)); if(r == -1) { if(errno == EAGAIN || errno == EINTR) { /* continue to read later */ return 0; } log_msg(LOG_ERR, "dnstap collector: read failed: %s", strerror(errno)); return 0; } buffer_skip(buf, r); if(buffer_position(buf) < 4) return 0; /* continue to read more msglen later */ } /* msglen complete */ msglen = buffer_read_u32_at(buf, 0); /* assert we have enough space, if we don't and we wanted to continue, * we would have to skip the message somehow, but that should never * happen because send_buffer and receive_buffer have the same size */ assert(buffer_capacity(buf) >= msglen + 4); r = read(fd, buffer_current(buf), msglen - (buffer_position(buf) - 4)); if(r == -1) { if(errno == EAGAIN || errno == EINTR) { /* continue to read later */ return 0; } log_msg(LOG_ERR, "dnstap collector: read failed: %s", strerror(errno)); return 0; } buffer_skip(buf, r); if(buffer_position(buf) < 4 + msglen) return 0; /* read more msg later */ /* msg complete */ buffer_flip(buf); return 1; } /* submit the content of the buffer received to dnstap */ static void dt_submit_content(struct dt_env* dt_env, struct buffer* buf) { uint8_t is_response, is_tcp; #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; size_t pktlen; uint8_t* data; size_t zonelen; uint8_t* zone; /* parse content from buffer */ if(!buffer_available(buf, 4+1+4)) return; buffer_skip(buf, 4); /* skip msglen */ is_response = buffer_read_u8(buf); addrlen = buffer_read_u32(buf); if(addrlen > sizeof(addr)) return; if(!buffer_available(buf, addrlen)) return; buffer_read(buf, &addr, addrlen); if(!buffer_available(buf, 1+4)) return; is_tcp = buffer_read_u8(buf); pktlen = buffer_read_u32(buf); if(!buffer_available(buf, pktlen)) return; data = buffer_current(buf); buffer_skip(buf, pktlen); if(!buffer_available(buf, 4)) return; zonelen = buffer_read_u32(buf); if(zonelen == 0) { zone = NULL; } else { if(zonelen > MAXDOMAINLEN) return; if(!buffer_available(buf, zonelen)) return; zone = buffer_current(buf); buffer_skip(buf, zonelen); } /* submit it */ if(is_response) { dt_msg_send_auth_response(dt_env, &addr, is_tcp, zone, zonelen, data, pktlen); } else { dt_msg_send_auth_query(dt_env, &addr, is_tcp, zone, zonelen, data, pktlen); } } /* handle input from worker for dnstap */ void dt_handle_input(int fd, short event, void* arg) { struct dt_collector_input* dt_input = (struct dt_collector_input*)arg; if((event&EV_READ) != 0) { /* read */ if(!read_into_buffer(fd, dt_input->buffer)) return; /* once data is complete, write it to dnstap */ VERBOSITY(4, (LOG_INFO, "dnstap collector: received msg len %d", (int)buffer_remaining(dt_input->buffer))); if(dt_input->dt_collector->dt_env) { dt_submit_content(dt_input->dt_collector->dt_env, dt_input->buffer); } /* clear buffer for next message */ buffer_clear(dt_input->buffer); } } /* init dnstap */ static void dt_init_dnstap(struct dt_collector* dt_col, struct nsd* nsd) { int num_workers = 1; #ifdef HAVE_CHROOT if(nsd->chrootdir && nsd->chrootdir[0]) { int l = strlen(nsd->chrootdir)-1; /* ends in trailing slash */ if (nsd->options->dnstap_socket_path && nsd->options->dnstap_socket_path[0] == '/' && strncmp(nsd->options->dnstap_socket_path, nsd->chrootdir, l) == 0) nsd->options->dnstap_socket_path += l; } #endif dt_col->dt_env = dt_create(nsd->options->dnstap_socket_path, num_workers); if(!dt_col->dt_env) { log_msg(LOG_ERR, "could not create dnstap env"); return; } dt_apply_cfg(dt_col->dt_env, nsd->options); dt_init(dt_col->dt_env); } /* cleanup dt collector process for exit */ static void dt_collector_cleanup(struct dt_collector* dt_col, struct nsd* nsd) { int i; dt_delete(dt_col->dt_env); event_del(dt_col->cmd_event); for(i=0; icount; i++) { event_del(dt_col->inputs[i].event); } dt_collector_close(dt_col, nsd); event_base_free(dt_col->event_base); #ifdef MEMCLEAN free(dt_col->cmd_event); if(dt_col->inputs) { for(i=0; icount; i++) { free(dt_col->inputs[i].event); } free(dt_col->inputs); } dt_collector_destroy(dt_col, nsd); #endif } /* attach events to the event base to listen to the workers and cmd channel */ static void dt_attach_events(struct dt_collector* dt_col, struct nsd* nsd) { int i; /* create event base */ dt_col->event_base = nsd_child_event_base(); if(!dt_col->event_base) { error("dnstap collector: event_base create failed"); } /* add command handler */ dt_col->cmd_event = (struct event*)xalloc_zero( sizeof(*dt_col->cmd_event)); event_set(dt_col->cmd_event, dt_col->cmd_socket_dt, EV_PERSIST|EV_READ, dt_handle_cmd_from_nsd, dt_col); if(event_base_set(dt_col->event_base, dt_col->cmd_event) != 0) log_msg(LOG_ERR, "dnstap collector: event_base_set failed"); if(event_add(dt_col->cmd_event, NULL) != 0) log_msg(LOG_ERR, "dnstap collector: event_add failed"); /* add worker input handlers */ dt_col->inputs = xalloc_array_zero(dt_col->count, sizeof(*dt_col->inputs)); for(i=0; icount; i++) { dt_col->inputs[i].dt_collector = dt_col; dt_col->inputs[i].event = (struct event*)xalloc_zero( sizeof(struct event)); event_set(dt_col->inputs[i].event, nsd->dt_collector_fd_recv[i], EV_PERSIST|EV_READ, dt_handle_input, &dt_col->inputs[i]); if(event_base_set(dt_col->event_base, dt_col->inputs[i].event) != 0) log_msg(LOG_ERR, "dnstap collector: event_base_set failed"); if(event_add(dt_col->inputs[i].event, NULL) != 0) log_msg(LOG_ERR, "dnstap collector: event_add failed"); dt_col->inputs[i].buffer = buffer_create(dt_col->region, /* msglen + is_response + addrlen + is_tcp + packetlen + packet + zonelen + zone + spare + addr */ 4+1+4+1+4+TCP_MAX_MESSAGE_LEN+4+MAXHOSTNAMELEN + 32 + #ifdef INET6 sizeof(struct sockaddr_storage) #else sizeof(struct sockaddr_in) #endif ); assert(buffer_capacity(dt_col->inputs[i].buffer) == buffer_capacity(dt_col->send_buffer)); } } /* the dnstap collector process main routine */ static void dt_collector_run(struct dt_collector* dt_col, struct nsd* nsd) { /* init dnstap */ VERBOSITY(1, (LOG_INFO, "dnstap collector started")); dt_init_dnstap(dt_col, nsd); dt_attach_events(dt_col, nsd); /* run */ if(event_base_loop(dt_col->event_base, 0) == -1) { error("dnstap collector: event_base_loop failed"); } /* cleanup and done */ VERBOSITY(1, (LOG_INFO, "dnstap collector stopped")); dt_collector_cleanup(dt_col, nsd); exit(0); } void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd) { /* fork */ dt_col->dt_pid = fork(); if(dt_col->dt_pid == -1) { error("dnstap_collector: fork failed: %s", strerror(errno)); } if(dt_col->dt_pid == 0) { /* the dt collector process is this */ /* close the nsd side of the command channel */ close(dt_col->cmd_socket_nsd); dt_col->cmd_socket_nsd = -1; dt_collector_run(dt_col, nsd); /* NOTREACH */ exit(0); } else { /* the parent continues on, with starting NSD */ /* close the dt side of the command channel */ close(dt_col->cmd_socket_dt); dt_col->cmd_socket_dt = -1; } } /* put data for sending to the collector process into the buffer */ static int prep_send_data(struct buffer* buf, uint8_t is_response, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone) { buffer_clear(buf); if(!buffer_available(buf, 4+1+4+addrlen+1+4+buffer_remaining(packet))) return 0; /* does not fit in send_buffer, log is dropped */ buffer_skip(buf, 4); /* the length of the message goes here */ buffer_write_u8(buf, is_response); buffer_write_u32(buf, addrlen); buffer_write(buf, addr, (size_t)addrlen); buffer_write_u8(buf, (is_tcp?1:0)); buffer_write_u32(buf, buffer_remaining(packet)); buffer_write(buf, buffer_begin(packet), buffer_remaining(packet)); if(zone && zone->apex && domain_dname(zone->apex)) { if(!buffer_available(buf, 4 + domain_dname(zone->apex)->name_size)) return 0; buffer_write_u32(buf, domain_dname(zone->apex)->name_size); buffer_write(buf, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size); } else { if(!buffer_available(buf, 4)) return 0; buffer_write_u32(buf, 0); } buffer_flip(buf); /* write length of message */ buffer_write_u32_at(buf, 0, buffer_remaining(buf)-4); return 1; } /* attempt to write buffer to socket, if it blocks do not write it. */ static void attempt_to_write(int s, uint8_t* data, size_t len) { size_t total = 0; ssize_t r; while(total < len) { r = write(s, data+total, len-total); if(r == -1) { if(errno == EAGAIN && total == 0) { /* on first write part, check if pipe is full, * if the nonblocking fd blocks, then drop * the message */ return; } if(errno != EAGAIN && errno != EINTR) { /* some sort of error, print it and drop it */ log_msg(LOG_ERR, "dnstap collector: write failed: %s", strerror(errno)); return; } /* continue and write this again */ /* for EINTR, we have to do this, * for EAGAIN, if the first part succeeded, we have * to continue to write the remainder of the message, * because otherwise partial messages confuse the * receiver. */ continue; } total += r; } } void dt_collector_submit_auth_query(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet) { if(!nsd->dt_collector) return; if(!nsd->options->dnstap_log_auth_query_messages) return; VERBOSITY(4, (LOG_INFO, "dnstap submit auth query")); /* marshal data into send buffer */ if(!prep_send_data(nsd->dt_collector->send_buffer, 0, addr, addrlen, is_tcp, packet, NULL)) return; /* probably did not fit in buffer */ /* attempt to send data; do not block */ attempt_to_write(nsd->dt_collector_fd_send[nsd->this_child->child_num], buffer_begin(nsd->dt_collector->send_buffer), buffer_remaining(nsd->dt_collector->send_buffer)); } void dt_collector_submit_auth_response(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone) { if(!nsd->dt_collector) return; if(!nsd->options->dnstap_log_auth_response_messages) return; VERBOSITY(4, (LOG_INFO, "dnstap submit auth response")); /* marshal data into send buffer */ if(!prep_send_data(nsd->dt_collector->send_buffer, 1, addr, addrlen, is_tcp, packet, zone)) return; /* probably did not fit in buffer */ /* attempt to send data; do not block */ attempt_to_write(nsd->dt_collector_fd_send[nsd->this_child->child_num], buffer_begin(nsd->dt_collector->send_buffer), buffer_remaining(nsd->dt_collector->send_buffer)); } nsd-4.1.26/dnstap/dnstap_collector.h0000664000175000017500000000572313355417226017046 0ustar wouterwouter/* * dnstap/dnstap_collector.h -- nsd collector process for dnstap information * * Copyright (c) 2018, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef DNSTAP_COLLECTOR_H #define DNSTAP_COLLECTOR_H struct dt_env; struct nsd; struct event_base; struct event; struct dt_collector_input; struct zone; struct buffer; struct region; /* information for the dnstap collector process. It collects information * for dnstap from the worker processes. And writes them to the dnstap * socket. */ struct dt_collector { /* dnstap env for the write to the dnstap socket */ struct dt_env* dt_env; /* number of workers to collect from */ int count; /* socketpair for communication between (xfrd) and the * dnstap collector process. If closed, the collector process * exits. The collector closes the other side of the socketpair, so * that if xfrd exits, so does the dnstap collector */ int cmd_socket_dt, cmd_socket_nsd; /* the pid of the dt collector process (0 on that process) */ pid_t dt_pid; /* in the collector process, the event base */ struct event_base* event_base; /* in the collector process, the cmd handle event */ struct event* cmd_event; /* in the collector process, array size count of input per worker */ struct dt_collector_input* inputs; /* region for buffers */ struct region* region; /* buffer for sending data to the collector */ struct buffer* send_buffer; }; /* information per worker to get input from that worker. */ struct dt_collector_input { /* the collector this is part of (for use in callbacks) */ struct dt_collector* dt_collector; /* the event to listen to the datagrams to process for that worker*/ struct event* event; /* buffer to store the datagrams while they are read in */ struct buffer* buffer; }; /* create dt_collector process structure and dt_env */ struct dt_collector* dt_collector_create(struct nsd* nsd); /* destroy the dt_collector structure */ void dt_collector_destroy(struct dt_collector* dt_col, struct nsd* nsd); /* close file descriptors */ void dt_collector_close(struct dt_collector* dt_col, struct nsd* nsd); /* start the collector process */ void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd); /* submit auth query from worker. It attempts to send it to the collector, * if the nonblocking fails, then it silently skips it. So it does not block * on the log. */ void dt_collector_submit_auth_query(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet); /* submit auth response from worker. It attempts to send it to the collector, * if the nonblocking fails, then it silently skips it. So it does not block * on the log. */ void dt_collector_submit_auth_response(struct nsd* nsd, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif socklen_t addrlen, int is_tcp, struct buffer* packet, struct zone* zone); #endif /* DNSTAP_COLLECTOR_H */ nsd-4.1.26/dnstap/dnstap.c0000664000175000017500000002610113363322066014760 0ustar wouterwouter/* dnstap support for NSD */ /* * Copyright (c) 2013-2014, Farsight Security, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "dnstap/dnstap_config.h" #ifdef USE_DNSTAP #include "config.h" #include #include #ifdef HAVE_SYS_STAT_H #include #endif #include #include #include "util.h" #include "options.h" #include #include #include "dnstap/dnstap.h" #include "dnstap/dnstap.pb-c.h" #define DNSTAP_CONTENT_TYPE "protobuf:dnstap.Dnstap" #define DNSTAP_INITIAL_BUF_SIZE 256 struct dt_msg { void *buf; size_t len_buf; Dnstap__Dnstap d; Dnstap__Message m; }; static int dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz) { ProtobufCBufferSimple sbuf; memset(&sbuf, 0, sizeof(sbuf)); sbuf.base.append = protobuf_c_buffer_simple_append; sbuf.len = 0; sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE; sbuf.data = malloc(sbuf.alloced); if (sbuf.data == NULL) return 0; sbuf.must_free_data = 1; *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf); if (sbuf.data == NULL) return 0; *buf = sbuf.data; return 1; } static void dt_send(const struct dt_env *env, void *buf, size_t len_buf) { fstrm_res res; if (!buf) return; res = fstrm_iothr_submit(env->iothr, env->ioq, buf, len_buf, fstrm_free_wrapper, NULL); if (res != fstrm_res_success) free(buf); } static void dt_msg_init(const struct dt_env *env, struct dt_msg *dm, Dnstap__Message__Type mtype) { memset(dm, 0, sizeof(*dm)); dm->d.base.descriptor = &dnstap__dnstap__descriptor; dm->m.base.descriptor = &dnstap__message__descriptor; dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE; dm->d.message = &dm->m; dm->m.type = mtype; if (env->identity != NULL) { dm->d.identity.data = (uint8_t *) env->identity; dm->d.identity.len = (size_t) env->len_identity; dm->d.has_identity = 1; } if (env->version != NULL) { dm->d.version.data = (uint8_t *) env->version; dm->d.version.len = (size_t) env->len_version; dm->d.has_version = 1; } } /* check that the socket file can be opened and exists, print error if not */ static void check_socket_file(const char* socket_path) { struct stat statbuf; memset(&statbuf, 0, sizeof(statbuf)); if(stat(socket_path, &statbuf) < 0) { log_msg(LOG_WARNING, "could not open dnstap-socket-path: %s, %s", socket_path, strerror(errno)); } } struct dt_env * dt_create(const char *socket_path, unsigned num_workers) { #ifndef NDEBUG fstrm_res res; #endif struct dt_env *env; struct fstrm_iothr_options *fopt; struct fstrm_unix_writer_options *fuwopt; struct fstrm_writer *fw; struct fstrm_writer_options *fwopt; VERBOSITY(1, (LOG_INFO, "attempting to connect to dnstap socket %s", socket_path)); assert(socket_path != NULL); assert(num_workers > 0); check_socket_file(socket_path); env = (struct dt_env *) calloc(1, sizeof(struct dt_env)); if (!env) return NULL; fwopt = fstrm_writer_options_init(); #ifndef NDEBUG res = #else (void) #endif fstrm_writer_options_add_content_type(fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1); assert(res == fstrm_res_success); fuwopt = fstrm_unix_writer_options_init(); fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path); fw = fstrm_unix_writer_init(fuwopt, fwopt); assert(fw != NULL); fopt = fstrm_iothr_options_init(); fstrm_iothr_options_set_num_input_queues(fopt, num_workers); env->iothr = fstrm_iothr_init(fopt, &fw); if (env->iothr == NULL) { log_msg(LOG_ERR, "dt_create: fstrm_iothr_init() failed"); fstrm_writer_destroy(&fw); free(env); env = NULL; } fstrm_iothr_options_destroy(&fopt); fstrm_unix_writer_options_destroy(&fuwopt); fstrm_writer_options_destroy(&fwopt); return env; } static void dt_apply_identity(struct dt_env *env, struct nsd_options *cfg) { char buf[MAXHOSTNAMELEN+1]; if (!cfg->dnstap_send_identity) return; free(env->identity); if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) { if (gethostname(buf, MAXHOSTNAMELEN) == 0) { buf[MAXHOSTNAMELEN] = 0; env->identity = strdup(buf); } else { error("dt_apply_identity: gethostname() failed"); } } else { env->identity = strdup(cfg->dnstap_identity); } if (env->identity == NULL) error("dt_apply_identity: strdup() failed"); env->len_identity = (unsigned int)strlen(env->identity); VERBOSITY(1, (LOG_INFO, "dnstap identity field set to \"%s\"", env->identity)); } static void dt_apply_version(struct dt_env *env, struct nsd_options *cfg) { if (!cfg->dnstap_send_version) return; free(env->version); if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0) env->version = strdup(PACKAGE_STRING); else env->version = strdup(cfg->dnstap_version); if (env->version == NULL) error("dt_apply_version: strdup() failed"); env->len_version = (unsigned int)strlen(env->version); VERBOSITY(1, (LOG_INFO, "dnstap version field set to \"%s\"", env->version)); } void dt_apply_cfg(struct dt_env *env, struct nsd_options *cfg) { if (!cfg->dnstap_enable) return; dt_apply_identity(env, cfg); dt_apply_version(env, cfg); if ((env->log_auth_query_messages = (unsigned int) cfg->dnstap_log_auth_query_messages)) { VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_QUERY enabled")); } if ((env->log_auth_response_messages = (unsigned int) cfg->dnstap_log_auth_response_messages)) { VERBOSITY(1, (LOG_INFO, "dnstap Message/AUTH_RESPONSE enabled")); } } int dt_init(struct dt_env *env) { env->ioq = fstrm_iothr_get_input_queue(env->iothr); if (env->ioq == NULL) return 0; return 1; } void dt_delete(struct dt_env *env) { if (!env) return; VERBOSITY(1, (LOG_INFO, "closing dnstap socket")); fstrm_iothr_destroy(&env->iothr); free(env->identity); free(env->version); free(env); } static void dt_fill_timeval(const struct timeval *tv, uint64_t *time_sec, protobuf_c_boolean *has_time_sec, uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec) { #ifndef S_SPLINT_S *time_sec = tv->tv_sec; *time_nsec = tv->tv_usec * 1000; #endif *has_time_sec = 1; *has_time_nsec = 1; } static void dt_fill_buffer(uint8_t* pkt, size_t pktlen, ProtobufCBinaryData *p, protobuf_c_boolean *has) { p->len = pktlen; p->data = pkt; *has = 1; } static void dt_msg_fill_net(struct dt_msg *dm, #ifdef INET6 struct sockaddr_storage *ss, #else struct sockaddr_in *ss, #endif int is_tcp, ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr, uint32_t *port, protobuf_c_boolean *has_port) { #ifdef INET6 assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET); if (ss->ss_family == AF_INET6) { struct sockaddr_in6 *s = (struct sockaddr_in6 *) ss; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ addr->data = s->sin6_addr.s6_addr; addr->len = 16; /* IPv6 */ *has_addr = 1; /* port: query_port or response_port */ *port = ntohs(s->sin6_port); *has_port = 1; } else if (ss->ss_family == AF_INET) { #else if (ss->ss_family == AF_INET) { #endif /* INET6 */ struct sockaddr_in *s = (struct sockaddr_in *) ss; /* socket_family */ dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET; dm->m.has_socket_family = 1; /* addr: query_address or response_address */ addr->data = (uint8_t *) &s->sin_addr.s_addr; addr->len = 4; /* IPv4 */ *has_addr = 1; /* port: query_port or response_port */ *port = ntohs(s->sin_port); *has_port = 1; } if (!is_tcp) { /* socket_protocol */ dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP; dm->m.has_socket_protocol = 1; } else { /* socket_protocol */ dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP; dm->m.has_socket_protocol = 1; } } void dt_msg_send_auth_query(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen) { struct dt_msg dm; struct timeval qtime; gettimeofday(&qtime, NULL); /* type */ dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_QUERY); if(zone) { /* query_zone */ dm.m.query_zone.data = zone; dm.m.query_zone.len = zonelen; dm.m.has_query_zone = 1; } /* query_time */ dt_fill_timeval(&qtime, &dm.m.query_time_sec, &dm.m.has_query_time_sec, &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); /* query_message */ dt_fill_buffer(pkt, pktlen, &dm.m.query_message, &dm.m.has_query_message); /* socket_family, socket_protocol, query_address, query_port */ dt_msg_fill_net(&dm, addr, is_tcp, &dm.m.query_address, &dm.m.has_query_address, &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); } void dt_msg_send_auth_response(struct dt_env *env, #ifdef INET6 struct sockaddr_storage* addr, #else struct sockaddr_in* addr, #endif int is_tcp, uint8_t* zone, size_t zonelen, uint8_t* pkt, size_t pktlen) { struct dt_msg dm; struct timeval rtime; gettimeofday(&rtime, NULL); /* type */ dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__AUTH_RESPONSE); if(zone) { /* query_zone */ dm.m.query_zone.data = zone; dm.m.query_zone.len = zonelen; dm.m.has_query_zone = 1; } /* response_time */ dt_fill_timeval(&rtime, &dm.m.response_time_sec, &dm.m.has_response_time_sec, &dm.m.response_time_nsec, &dm.m.has_response_time_nsec); /* response_message */ dt_fill_buffer(pkt, pktlen, &dm.m.response_message, &dm.m.has_response_message); /* socket_family, socket_protocol, query_address, query_port */ dt_msg_fill_net(&dm, addr, is_tcp, &dm.m.query_address, &dm.m.has_query_address, &dm.m.query_port, &dm.m.has_query_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); } #endif /* USE_DNSTAP */ nsd-4.1.26/dnstap/dnstap.proto0000664000175000017500000002455613355344112015712 0ustar wouterwouter// dnstap: flexible, structured event replication format for DNS software // // This file contains the protobuf schemas for the "dnstap" structured event // replication format for DNS software. // Written in 2013-2014 by Farsight Security, Inc. // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this file to the public // domain worldwide. This file is distributed without any warranty. // // You should have received a copy of the CC0 Public Domain Dedication along // with this file. If not, see: // // . syntax = "proto2"; package dnstap; // "Dnstap": this is the top-level dnstap type, which is a "union" type that // contains other kinds of dnstap payloads, although currently only one type // of dnstap payload is defined. // See: https://developers.google.com/protocol-buffers/docs/techniques#union message Dnstap { // DNS server identity. // If enabled, this is the identity string of the DNS server which generated // this message. Typically this would be the same string as returned by an // "NSID" (RFC 5001) query. optional bytes identity = 1; // DNS server version. // If enabled, this is the version string of the DNS server which generated // this message. Typically this would be the same string as returned by a // "version.bind" query. optional bytes version = 2; // Extra data for this payload. // This field can be used for adding an arbitrary byte-string annotation to // the payload. No encoding or interpretation is applied or enforced. optional bytes extra = 3; // Identifies which field below is filled in. enum Type { MESSAGE = 1; } required Type type = 15; // One of the following will be filled in. optional Message message = 14; } // SocketFamily: the network protocol family of a socket. This specifies how // to interpret "network address" fields. enum SocketFamily { INET = 1; // IPv4 (RFC 791) INET6 = 2; // IPv6 (RFC 2460) } // SocketProtocol: the transport protocol of a socket. This specifies how to // interpret "transport port" fields. enum SocketProtocol { UDP = 1; // User Datagram Protocol (RFC 768) TCP = 2; // Transmission Control Protocol (RFC 793) } // Message: a wire-format (RFC 1035 section 4) DNS message and associated // metadata. Applications generating "Message" payloads should follow // certain requirements based on the MessageType, see below. message Message { // There are eight types of "Message" defined that correspond to the // four arrows in the following diagram, slightly modified from RFC 1035 // section 2: // +---------+ +----------+ +--------+ // | | query | | query | | // | Stub |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth. | // | Resolver| | Server | | Name | // | |<-SR--------CR-| |<-RR----AR-| Server | // +---------+ response | | response | | // +----------+ +--------+ // Each arrow has two Type values each, one for each "end" of each arrow, // because these are considered to be distinct events. Each end of each // arrow on the diagram above has been marked with a two-letter Type // mnemonic. Clockwise from upper left, these mnemonic values are: // // SQ: STUB_QUERY // CQ: CLIENT_QUERY // RQ: RESOLVER_QUERY // AQ: AUTH_QUERY // AR: AUTH_RESPONSE // RR: RESOLVER_RESPONSE // CR: CLIENT_RESPONSE // SR: STUB_RESPONSE // Two additional types of "Message" have been defined for the // "forwarding" case where an upstream DNS server is responsible for // further recursion. These are not shown on the diagram above, but have // the following mnemonic values: // FQ: FORWARDER_QUERY // FR: FORWARDER_RESPONSE // The "Message" Type values are defined below. enum Type { // AUTH_QUERY is a DNS query message received from a resolver by an // authoritative name server, from the perspective of the authoritative // name server. AUTH_QUERY = 1; // AUTH_RESPONSE is a DNS response message sent from an authoritative // name server to a resolver, from the perspective of the authoritative // name server. AUTH_RESPONSE = 2; // RESOLVER_QUERY is a DNS query message sent from a resolver to an // authoritative name server, from the perspective of the resolver. // Resolvers typically clear the RD (recursion desired) bit when // sending queries. RESOLVER_QUERY = 3; // RESOLVER_RESPONSE is a DNS response message received from an // authoritative name server by a resolver, from the perspective of // the resolver. RESOLVER_RESPONSE = 4; // CLIENT_QUERY is a DNS query message sent from a client to a DNS // server which is expected to perform further recursion, from the // perspective of the DNS server. The client may be a stub resolver or // forwarder or some other type of software which typically sets the RD // (recursion desired) bit when querying the DNS server. The DNS server // may be a simple forwarding proxy or it may be a full recursive // resolver. CLIENT_QUERY = 5; // CLIENT_RESPONSE is a DNS response message sent from a DNS server to // a client, from the perspective of the DNS server. The DNS server // typically sets the RA (recursion available) bit when responding. CLIENT_RESPONSE = 6; // FORWARDER_QUERY is a DNS query message sent from a downstream DNS // server to an upstream DNS server which is expected to perform // further recursion, from the perspective of the downstream DNS // server. FORWARDER_QUERY = 7; // FORWARDER_RESPONSE is a DNS response message sent from an upstream // DNS server performing recursion to a downstream DNS server, from the // perspective of the downstream DNS server. FORWARDER_RESPONSE = 8; // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS // server, from the perspective of the stub resolver. STUB_QUERY = 9; // STUB_RESPONSE is a DNS response message sent from a DNS server to a // stub resolver, from the perspective of the stub resolver. STUB_RESPONSE = 10; } // One of the Type values described above. required Type type = 1; // One of the SocketFamily values described above. optional SocketFamily socket_family = 2; // One of the SocketProtocol values described above. optional SocketProtocol socket_protocol = 3; // The network address of the message initiator. // For SocketFamily INET, this field is 4 octets (IPv4 address). // For SocketFamily INET6, this field is 16 octets (IPv6 address). optional bytes query_address = 4; // The network address of the message responder. // For SocketFamily INET, this field is 4 octets (IPv4 address). // For SocketFamily INET6, this field is 16 octets (IPv6 address). optional bytes response_address = 5; // The transport port of the message initiator. // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. optional uint32 query_port = 6; // The transport port of the message responder. // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. optional uint32 response_port = 7; // The time at which the DNS query message was sent or received, depending // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. // This is the number of seconds since the UNIX epoch. optional uint64 query_time_sec = 8; // The time at which the DNS query message was sent or received. // This is the seconds fraction, expressed as a count of nanoseconds. optional fixed32 query_time_nsec = 9; // The initiator's original wire-format DNS query message, verbatim. optional bytes query_message = 10; // The "zone" or "bailiwick" pertaining to the DNS query message. // This is a wire-format DNS domain name. optional bytes query_zone = 11; // The time at which the DNS response message was sent or received, // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or // CLIENT_RESPONSE. // This is the number of seconds since the UNIX epoch. optional uint64 response_time_sec = 12; // The time at which the DNS response message was sent or received. // This is the seconds fraction, expressed as a count of nanoseconds. optional fixed32 response_time_nsec = 13; // The responder's original wire-format DNS response message, verbatim. optional bytes response_message = 14; } // All fields except for 'type' in the Message schema are optional. // It is recommended that at least the following fields be filled in for // particular types of Messages. // AUTH_QUERY: // socket_family, socket_protocol // query_address, query_port // query_message // query_time_sec, query_time_nsec // AUTH_RESPONSE: // socket_family, socket_protocol // query_address, query_port // query_time_sec, query_time_nsec // response_message // response_time_sec, response_time_nsec // RESOLVER_QUERY: // socket_family, socket_protocol // query_name, query_type, query_class // query_message // query_time_sec, query_time_nsec // query_zone // response_address, response_port // RESOLVER_RESPONSE: // socket_family, socket_protocol // query_name, query_type, query_class // query_time_sec, query_time_nsec // query_zone // response_address, response_port // response_message // response_time_sec, response_time_nsec // CLIENT_QUERY: // socket_family, socket_protocol // query_message // query_time_sec, query_time_nsec // CLIENT_RESPONSE: // socket_family, socket_protocol // query_time_sec, query_time_nsec // response_message // response_time_sec, response_time_nsec nsd-4.1.26/dnstap/dnstap.m40000664000175000017500000000420313355344112015052 0ustar wouterwouter# dnstap.m4 # dt_DNSTAP(default_dnstap_socket_path, [action-if-true], [action-if-false]) # -------------------------------------------------------------------------- # Check for required dnstap libraries and add dnstap configure args. AC_DEFUN([dt_DNSTAP], [ AC_ARG_ENABLE([dnstap], AS_HELP_STRING([--enable-dnstap], [Enable dnstap support (requires fstrm, protobuf-c)]), [opt_dnstap=$enableval], [opt_dnstap=no]) AC_ARG_WITH([dnstap-socket-path], AS_HELP_STRING([--with-dnstap-socket-path=pathname], [set default dnstap socket path]), [opt_dnstap_socket_path=$withval], [opt_dnstap_socket_path="$1"]) if test "x$opt_dnstap" != "xno"; then AC_PATH_PROG([PROTOC_C], [protoc-c]) if test -z "$PROTOC_C"; then AC_MSG_ERROR([The protoc-c program was not found. Please install protobuf-c!]) fi AC_ARG_WITH([protobuf-c], AC_HELP_STRING([--with-protobuf-c=path], [Path where protobuf-c is installed, for dnstap]), [ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f $withval/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I$withval/include/google" else CFLAGS="$CFLAGS -I$withval/include" fi LDFLAGS="$LDFLAGS -L$withval/lib" ], [ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0 if test -f /usr/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/include/google" else if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then CFLAGS="$CFLAGS -I/usr/local/include/google" LDFLAGS="$LDFLAGS -L/usr/local/lib" fi fi ]) AC_ARG_WITH([libfstrm], AC_HELP_STRING([--with-libfstrm=path], [Path where libfstrm is installed, for dnstap]), [ CFLAGS="$CFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib" ]) AC_SEARCH_LIBS([fstrm_iothr_init], [fstrm], [], AC_MSG_ERROR([The fstrm library was not found. Please install fstrm!])) AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [], AC_MSG_ERROR([The protobuf-c library was not found. Please install protobuf-c!])) $2 else $3 fi ]) nsd-4.1.26/dname.c0000664000175000017500000003027412502041003013247 0ustar wouterwouter/* * dname.c -- Domain name handling. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "dns.h" #include "dname.h" #include "query.h" const dname_type * dname_make(region_type *region, const uint8_t *name, int normalize) { size_t name_size = 0; uint8_t label_offsets[MAXDOMAINLEN]; uint8_t label_count = 0; const uint8_t *label = name; dname_type *result; ssize_t i; assert(name); while (1) { if (label_is_pointer(label)) return NULL; label_offsets[label_count] = (uint8_t) (label - name); ++label_count; name_size += label_length(label) + 1; if (label_is_root(label)) break; label = label_next(label); } if (name_size > MAXDOMAINLEN) return NULL; assert(label_count <= MAXDOMAINLEN / 2 + 1); /* Reverse label offsets. */ for (i = 0; i < label_count / 2; ++i) { uint8_t tmp = label_offsets[i]; label_offsets[i] = label_offsets[label_count - i - 1]; label_offsets[label_count - i - 1] = tmp; } result = (dname_type *) region_alloc( region, (sizeof(dname_type) + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t))); result->name_size = name_size; result->label_count = label_count; memcpy((uint8_t *) dname_label_offsets(result), label_offsets, label_count * sizeof(uint8_t)); if (normalize) { uint8_t *dst = (uint8_t *) dname_name(result); const uint8_t *src = name; while (!label_is_root(src)) { ssize_t len = label_length(src); *dst++ = *src++; for (i = 0; i < len; ++i) { *dst++ = DNAME_NORMALIZE((unsigned char)*src++); } } *dst = *src; } else { memcpy((uint8_t *) dname_name(result), name, name_size * sizeof(uint8_t)); } return result; } const dname_type * dname_make_from_packet(region_type *region, buffer_type *packet, int allow_pointers, int normalize) { uint8_t buf[MAXDOMAINLEN + 1]; if(!dname_make_wire_from_packet(buf, packet, allow_pointers)) return 0; return dname_make(region, buf, normalize); } int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers) { int done = 0; uint8_t visited[(MAX_PACKET_SIZE+7)/8]; size_t dname_length = 0; const uint8_t *label; ssize_t mark = -1; memset(visited, 0, (buffer_limit(packet)+7)/8); while (!done) { if (!buffer_available(packet, 1)) { /* error("dname out of bounds"); */ return 0; } if (get_bit(visited, buffer_position(packet))) { /* error("dname loops"); */ return 0; } set_bit(visited, buffer_position(packet)); label = buffer_current(packet); if (label_is_pointer(label)) { size_t pointer; if (!allow_pointers) { return 0; } if (!buffer_available(packet, 2)) { /* error("dname pointer out of bounds"); */ return 0; } pointer = label_pointer_location(label); if (pointer >= buffer_limit(packet)) { /* error("dname pointer points outside packet"); */ return 0; } buffer_skip(packet, 2); if (mark == -1) { mark = buffer_position(packet); } buffer_set_position(packet, pointer); } else if (label_is_normal(label)) { size_t length = label_length(label) + 1; done = label_is_root(label); if (!buffer_available(packet, length)) { /* error("dname label out of bounds"); */ return 0; } if (dname_length + length >= MAXDOMAINLEN+1) { /* error("dname too large"); */ return 0; } buffer_read(packet, buf + dname_length, length); dname_length += length; } else { /* error("bad label type"); */ return 0; } } if (mark != -1) { buffer_set_position(packet, mark); } return dname_length; } const dname_type * dname_parse(region_type *region, const char *name) { uint8_t dname[MAXDOMAINLEN]; if(!dname_parse_wire(dname, name)) return 0; return dname_make(region, dname, 1); } int dname_parse_wire(uint8_t* dname, const char* name) { const uint8_t *s = (const uint8_t *) name; uint8_t *h; uint8_t *p; uint8_t *d = dname; size_t label_length; if (strcmp(name, ".") == 0) { /* Root domain. */ dname[0] = 0; return 1; } for (h = d, p = h + 1; *s; ++s, ++p) { if (p - dname >= MAXDOMAINLEN) { return 0; } switch (*s) { case '.': if (p == h + 1) { /* Empty label. */ return 0; } else { label_length = p - h - 1; if (label_length > MAXLABELLEN) { return 0; } *h = label_length; h = p; } break; case '\\': /* Handle escaped characters (RFC1035 5.1) */ if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) { int val = (hexdigit_to_int(s[1]) * 100 + hexdigit_to_int(s[2]) * 10 + hexdigit_to_int(s[3])); if (0 <= val && val <= 255) { s += 3; *p = val; } else { *p = *++s; } } else if (s[1] != '\0') { *p = *++s; } break; default: *p = *s; break; } } if (p != h + 1) { /* Terminate last label. */ label_length = p - h - 1; if (label_length > MAXLABELLEN) { return 0; } *h = label_length; h = p; } /* Add root label. */ if (h - dname >= MAXDOMAINLEN) { return 0; } *h = 0; return p-dname; } const dname_type * dname_copy(region_type *region, const dname_type *dname) { return (dname_type *) region_alloc_init( region, dname, dname_total_size(dname)); } const dname_type * dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count) { if (!dname) return NULL; if (label_count == 0) { /* Always copy the root label. */ label_count = 1; } assert(label_count <= dname->label_count); return dname_make(region, dname_label(dname, label_count - 1), 0); } const dname_type * dname_origin(region_type *region, const dname_type *dname) { return dname_partial_copy(region, dname, dname->label_count - 1); } int dname_is_subdomain(const dname_type *left, const dname_type *right) { uint8_t i; if (left->label_count < right->label_count) return 0; for (i = 1; i < right->label_count; ++i) { if (label_compare(dname_label(left, i), dname_label(right, i)) != 0) return 0; } return 1; } int dname_compare(const dname_type *left, const dname_type *right) { int result; uint8_t label_count; uint8_t i; assert(left); assert(right); if (left == right) { return 0; } label_count = (left->label_count <= right->label_count ? left->label_count : right->label_count); /* Skip the root label by starting at label 1. */ for (i = 1; i < label_count; ++i) { result = label_compare(dname_label(left, i), dname_label(right, i)); if (result) { return result; } } /* Dname with the fewest labels is "first". */ /* the subtraction works because the size of int is much larger than * the label count and the values won't wrap around */ return (int) left->label_count - (int) right->label_count; } int label_compare(const uint8_t *left, const uint8_t *right) { int left_length; int right_length; size_t size; int result; assert(left); assert(right); assert(label_is_normal(left)); assert(label_is_normal(right)); left_length = label_length(left); right_length = label_length(right); size = left_length < right_length ? left_length : right_length; result = memcmp(label_data(left), label_data(right), size); if (result) { return result; } else { /* the subtraction works because the size of int is much * larger than the lengths and the values won't wrap around */ return (int) left_length - (int) right_length; } } uint8_t dname_label_match_count(const dname_type *left, const dname_type *right) { uint8_t i; assert(left); assert(right); for (i = 1; i < left->label_count && i < right->label_count; ++i) { if (label_compare(dname_label(left, i), dname_label(right, i)) != 0) { return i; } } return i; } const char * dname_to_string(const dname_type *dname, const dname_type *origin) { static char buf[MAXDOMAINLEN * 5]; size_t i; size_t labels_to_convert = dname->label_count - 1; int absolute = 1; char *dst; const uint8_t *src; if (dname->label_count == 1) { strlcpy(buf, ".", sizeof(buf)); return buf; } if (origin && dname_is_subdomain(dname, origin)) { int common_labels = dname_label_match_count(dname, origin); labels_to_convert = dname->label_count - common_labels; absolute = 0; } dst = buf; src = dname_name(dname); for (i = 0; i < labels_to_convert; ++i) { size_t len = label_length(src); size_t j; ++src; for (j = 0; j < len; ++j) { uint8_t ch = *src++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_') { *dst++ = ch; } else if (ch == '.' || ch == '\\') { *dst++ = '\\'; *dst++ = ch; } else { snprintf(dst, 5, "\\%03u", (unsigned int)ch); dst += 4; } } *dst++ = '.'; } if (absolute) { *dst = '\0'; } else { *--dst = '\0'; } return buf; } const dname_type * dname_make_from_label(region_type *region, const uint8_t *label, const size_t length) { uint8_t temp[MAXLABELLEN + 2]; assert(length > 0 && length <= MAXLABELLEN); temp[0] = length; memcpy(temp + 1, label, length * sizeof(uint8_t)); temp[length + 1] = '\000'; return dname_make(region, temp, 1); } const dname_type * dname_concatenate(region_type *region, const dname_type *left, const dname_type *right) { uint8_t temp[MAXDOMAINLEN]; assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN); memcpy(temp, dname_name(left), left->name_size - 1); memcpy(temp + left->name_size - 1, dname_name(right), right->name_size); return dname_make(region, temp, 0); } const dname_type * dname_replace(region_type* region, const dname_type* name, const dname_type* src, const dname_type* dest) { /* nomenclature: name is said to be .. x can be null. */ dname_type* res; int x_labels = name->label_count - src->label_count; int x_len = name->name_size - src->name_size; int i; assert(dname_is_subdomain(name, src)); /* check if final size is acceptable */ if(x_len+dest->name_size > MAXDOMAINLEN) return NULL; res = (dname_type*)region_alloc(region, sizeof(dname_type) + (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) *sizeof(uint8_t)); res->name_size = x_len+dest->name_size; res->label_count = x_labels+dest->label_count; for(i=0; ilabel_count; i++) ((uint8_t*)dname_label_offsets(res))[i] = dname_label_offsets(dest)[i] + x_len; for(i=dest->label_count; ilabel_count; i++) ((uint8_t*)dname_label_offsets(res))[i] = dname_label_offsets(name)[i - dest->label_count + src->label_count]; memcpy((uint8_t*)dname_name(res), dname_name(name), x_len); memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size); assert(dname_is_subdomain(res, dest)); return res; } char* wirelabel2str(const uint8_t* label) { static char buf[MAXDOMAINLEN*5+3]; char* p = buf; uint8_t lablen; lablen = *label++; while(lablen--) { uint8_t ch = *label++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_') { *p++ = ch; } else if (ch == '.' || ch == '\\') { *p++ = '\\'; *p++ = ch; } else { snprintf(p, 5, "\\%03u", (unsigned int)ch); p += 4; } } *p++ = 0; return buf; } char* wiredname2str(const uint8_t* dname) { static char buf[MAXDOMAINLEN*5+3]; char* p = buf; uint8_t lablen; if(*dname == 0) { strlcpy(buf, ".", sizeof(buf)); return buf; } lablen = *dname++; while(lablen) { while(lablen--) { uint8_t ch = *dname++; if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { *p++ = ch; } else if (ch == '.' || ch == '\\') { *p++ = '\\'; *p++ = ch; } else { snprintf(p, 5, "\\%03u", (unsigned int)ch); p += 4; } } lablen = *dname++; *p++ = '.'; } *p++ = 0; return buf; } int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len) { uint8_t i, lablen; while(len > 0) { /* check labellen */ if(*a != *b) return 0; lablen = *a++; b++; len--; /* malformed or compression ptr; we stop scanning */ if((lablen & 0xc0) || len < lablen) return (memcmp(a, b, len) == 0); /* check the label, lowercased */ for(i=0; i #include #include #include #include #include "lookup3.h" #include "util.h" /* mmap and friends */ #include #include #include #include /* for systems without, portable definition, failed-1 and async is a flag */ #ifndef MAP_FAILED #define MAP_FAILED ((void*)-1) #endif #ifndef MS_SYNC #define MS_SYNC 0 #endif /** move and fixup xl segment */ static void move_xl_segment(void* base, udb_base* udb, udb_void xl, udb_void n, uint64_t sz, uint64_t startseg); /** attempt to compact the data and move free space to the end */ static int udb_alloc_compact(void* base, udb_alloc* alloc); /** convert pointer to the data part to a pointer to the base of the chunk */ static udb_void chunk_from_dataptr(udb_void data) { /* we use that sizeof(udb_chunk_d) != sizeof(udb_xl_chunk_d) and * that xl_chunk_d is aligned on x**1024 boundaries. */ udb_void xl = data - sizeof(udb_xl_chunk_d); if( (xl & (UDB_ALLOC_CHUNK_SIZE-1)) == 0) return xl; return data - sizeof(udb_chunk_d); } udb_void chunk_from_dataptr_ext(udb_void data) { return chunk_from_dataptr(data); } #ifndef NDEBUG /** read last octet from a chunk */ static uint8_t chunk_get_last(void* base, udb_void chunk, int exp) { return *((uint8_t*)UDB_REL(base, chunk+(1<= 0 && exp <= 63); *((uint8_t*)UDB_REL(base, chunk+((uint64_t)1<fname = strdup(fname); if(!udb->fname) { log_msg(LOG_ERR, "out of memory"); free(udb); close(fd); return NULL; } udb->walkfunc = walkfunc; udb->walkarg = arg; udb->fd = fd; udb->ram_size = 1024; udb->ram_mask = (int)udb->ram_size - 1; udb->ram_hash = (udb_ptr**)xalloc_array_zero(sizeof(udb_ptr*), udb->ram_size); if(!udb->ram_hash) { free(udb->fname); free(udb); log_msg(LOG_ERR, "out of memory"); close(fd); return NULL; } /* read magic */ if((r=read(fd, &m, sizeof(m))) == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); goto fail; } else if(r != (ssize_t)sizeof(m)) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } /* TODO : what if bigendian and littleendian file, see magic */ if(m != UDB_MAGIC) { log_msg(LOG_ERR, "%s: wrong type of file", fname); goto fail; } /* read header */ if((r=read(fd, &g, sizeof(g))) == -1) { log_msg(LOG_ERR, "%s: %s\n", fname, strerror(errno)); goto fail; } else if(r != (ssize_t)sizeof(g)) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } if(g.version != 0) { log_msg(LOG_ERR, "%s: unknown file version %d", fname, (int)g.version); goto fail; } if(g.hsize < UDB_HEADER_SIZE) { log_msg(LOG_ERR, "%s: header size too small %d", fname, (int)g.hsize); goto fail; } if(g.hsize > UDB_HEADER_SIZE) { log_msg(LOG_WARNING, "%s: header size too large %d", fname, (int)g.hsize); goto fail; } if(g.clean_close != 1) { log_msg(LOG_WARNING, "%s: not cleanly closed %d", fname, (int)g.clean_close); goto fail; } if(g.dirty_alloc != 0) { log_msg(LOG_WARNING, "%s: not cleanly closed (alloc:%d)", fname, (int)g.dirty_alloc); goto fail; } /* check file size correctly written, for 4.0.2 nsd.db failure */ fsz = (uint64_t)lseek(fd, (off_t)0, SEEK_END); (void)lseek(fd, (off_t)0, SEEK_SET); if(g.fsize != fsz) { log_msg(LOG_WARNING, "%s: file size %llu but mmap header " "has size %llu", fname, (unsigned long long)fsz, (unsigned long long)g.fsize); goto fail; } /* mmap it */ if(g.fsize < UDB_HEADER_SIZE || g.fsize < g.hsize) { log_msg(LOG_ERR, "%s: file too short", fname); goto fail; } if(g.fsize > (uint64_t)400*1024*1024*1024*1024) /* 400 Tb */ { log_msg(LOG_WARNING, "%s: file size too large %llu", fname, (unsigned long long)g.fsize); goto fail; } udb->base_size = (size_t)g.fsize; #ifdef HAVE_MMAP /* note the size_t casts must be there for portability, on some * systems the layout of memory is otherwise broken. */ udb->base = mmap(NULL, (size_t)udb->base_size, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); #else udb->base = MAP_FAILED; errno = ENOSYS; #endif if(udb->base == MAP_FAILED) { udb->base = NULL; log_msg(LOG_ERR, "mmap(size %u) error: %s", (unsigned)udb->base_size, strerror(errno)); fail: close(fd); free(udb->fname); free(udb->ram_hash); free(udb); return NULL; } /* init completion */ udb->glob_data = (udb_glob_d*)(udb->base+sizeof(uint64_t)); r = 0; /* cannot be dirty because that is goto fail above */ if(udb->glob_data->dirty_alloc != udb_dirty_clean) r = 1; udb->alloc = udb_alloc_create(udb, (udb_alloc_d*)( (void*)udb->glob_data+sizeof(*udb->glob_data))); if(!udb->alloc) { log_msg(LOG_ERR, "out of memory"); udb_base_free(udb); return NULL; } if(r) { /* and compact now, or resume compacting */ udb_alloc_compact(udb, udb->alloc); udb_base_sync(udb, 1); } udb->glob_data->clean_close = 0; return udb; } udb_base* udb_base_create_read(const char* fname, udb_walk_relptr_func walkfunc, void* arg) { int fd = open(fname, O_RDWR); if(fd == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); return NULL; } return udb_base_create_fd(fname, fd, walkfunc, arg); } /** init new udb_global structure */ static void udb_glob_init_new(udb_glob_d* g) { memset(g, 0, sizeof(*g)); g->hsize = UDB_HEADER_SIZE; g->fsize = UDB_HEADER_SIZE; } /** write data to file and check result */ static int write_fdata(const char* fname, int fd, void* data, size_t len) { ssize_t w; if((w=write(fd, data, len)) == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); close(fd); return 0; } else if(w != (ssize_t)len) { log_msg(LOG_ERR, "%s: short write (disk full?)", fname); close(fd); return 0; } return 1; } udb_base* udb_base_create_new(const char* fname, udb_walk_relptr_func walkfunc, void* arg) { uint64_t m; udb_glob_d g; udb_alloc_d a; uint64_t endsize = UDB_HEADER_SIZE; uint64_t endexp = 0; int fd = open(fname, O_CREAT|O_RDWR, 0600); if(fd == -1) { log_msg(LOG_ERR, "%s: %s", fname, strerror(errno)); return NULL; } m = UDB_MAGIC; udb_glob_init_new(&g); udb_alloc_init_new(&a); g.clean_close = 1; /* write new data to file (closes fd on error) */ if(!write_fdata(fname, fd, &m, sizeof(m))) return NULL; if(!write_fdata(fname, fd, &g, sizeof(g))) return NULL; if(!write_fdata(fname, fd, &a, sizeof(a))) return NULL; if(!write_fdata(fname, fd, &endsize, sizeof(endsize))) return NULL; if(!write_fdata(fname, fd, &endexp, sizeof(endexp))) return NULL; /* rewind to start */ if(lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { log_msg(LOG_ERR, "%s: lseek %s", fname, strerror(errno)); close(fd); return NULL; } /* truncate to the right size */ if(ftruncate(fd, (off_t)g.fsize) < 0) { log_msg(LOG_ERR, "%s: ftruncate(%d): %s", fname, (int)g.fsize, strerror(errno)); close(fd); return NULL; } return udb_base_create_fd(fname, fd, walkfunc, arg); } /** shrink the udb base if it has unused space at the end */ static void udb_base_shrink(udb_base* udb, uint64_t nsize) { udb->glob_data->dirty_alloc = udb_dirty_fsize; udb->glob_data->fsize = nsize; /* sync, does not *seem* to be required on Linux, but it is certainly required on OpenBSD. Otherwise changed data is lost. */ #ifdef HAVE_MMAP msync(udb->base, udb->base_size, MS_ASYNC); #endif if(ftruncate(udb->fd, (off_t)nsize) != 0) { log_msg(LOG_ERR, "%s: ftruncate(%u) %s", udb->fname, (unsigned)nsize, strerror(errno)); } udb->glob_data->dirty_alloc = udb_dirty_clean; } void udb_base_close(udb_base* udb) { if(!udb) return; if(udb->fd != -1 && udb->base && udb->alloc) { uint64_t nsize = udb->alloc->disk->nextgrow; if(nsize < udb->base_size) udb_base_shrink(udb, nsize); } if(udb->fd != -1) { udb->glob_data->clean_close = 1; close(udb->fd); udb->fd = -1; } if(udb->base) { #ifdef HAVE_MMAP if(munmap(udb->base, udb->base_size) == -1) { log_msg(LOG_ERR, "munmap: %s", strerror(errno)); } #endif udb->base = NULL; } } void udb_base_free(udb_base* udb) { if(!udb) return; udb_base_close(udb); udb_alloc_delete(udb->alloc); free(udb->ram_hash); free(udb->fname); free(udb); } void udb_base_free_keep_mmap(udb_base* udb) { if(!udb) return; if(udb->fd != -1) { close(udb->fd); udb->fd = -1; } udb->base = NULL; udb_alloc_delete(udb->alloc); free(udb->ram_hash); free(udb->fname); free(udb); } void udb_base_sync(udb_base* udb, int wait) { if(!udb) return; #ifdef HAVE_MMAP if(msync(udb->base, udb->base_size, wait?MS_SYNC:MS_ASYNC) != 0) { log_msg(LOG_ERR, "msync(%s) error %s", udb->fname, strerror(errno)); } #else (void)wait; #endif } /** hash a chunk pointer */ static uint32_t chunk_hash_ptr(udb_void p) { /* put p into an array of uint32 */ uint32_t h[sizeof(p)/sizeof(uint32_t)]; memcpy(&h, &p, sizeof(h)); return hashword(h, sizeof(p)/sizeof(uint32_t), 0x8763); } /** check that the given pointer is on the bucket for the given offset */ int udb_ptr_is_on_bucket(udb_base* udb, udb_ptr* ptr, udb_void to) { uint32_t i = chunk_hash_ptr(to) & udb->ram_mask; udb_ptr* p; assert((size_t)i < udb->ram_size); for(p = udb->ram_hash[i]; p; p=p->next) { if(p == ptr) return 1; } return 0; } /** grow the ram array */ static void grow_ram_hash(udb_base* udb, udb_ptr** newhash) { size_t i; size_t osize= udb->ram_size; udb_ptr* p, *np; udb_ptr** oldhash = udb->ram_hash; udb->ram_size *= 2; udb->ram_mask <<= 1; udb->ram_mask |= 1; udb->ram_hash = newhash; /* have to link in every element in the old list into the new list*/ for(i=0; inext; /* link into newhash */ p->prev=NULL; p->next=newhash[chunk_hash_ptr(p->data)&udb->ram_mask]; if(p->next) p->next->prev = p; /* go to next element of oldhash */ p = np; } } free(oldhash); } void udb_base_link_ptr(udb_base* udb, udb_ptr* ptr) { uint32_t i; #ifdef UDB_CHECK assert(udb_valid_dataptr(udb, ptr->data)); /* must be to whole chunk*/ #endif udb->ram_num++; if(udb->ram_num == udb->ram_size && udb->ram_size<(size_t)0x7fffffff) { /* grow the array, if allocation succeeds */ udb_ptr** newram = (udb_ptr**)xalloc_array_zero( sizeof(udb_ptr*), udb->ram_size*2); if(newram) { grow_ram_hash(udb, newram); } } i = chunk_hash_ptr(ptr->data) & udb->ram_mask; assert((size_t)i < udb->ram_size); ptr->prev = NULL; ptr->next = udb->ram_hash[i]; udb->ram_hash[i] = ptr; if(ptr->next) ptr->next->prev = ptr; } void udb_base_unlink_ptr(udb_base* udb, udb_ptr* ptr) { assert(ptr->data); #ifdef UDB_CHECK assert(udb_valid_dataptr(udb, ptr->data)); /* ptr must be inited */ assert(udb_ptr_is_on_bucket(udb, ptr, ptr->data)); #endif udb->ram_num--; if(ptr->next) ptr->next->prev = ptr->prev; if(ptr->prev) ptr->prev->next = ptr->next; else { uint32_t i = chunk_hash_ptr(ptr->data) & udb->ram_mask; assert((size_t)i < udb->ram_size); udb->ram_hash[i] = ptr->next; } } /** change a set of ram ptrs to a new value */ static void udb_base_ram_ptr_edit(udb_base* udb, udb_void old, udb_void newd) { uint32_t io = chunk_hash_ptr(old) & udb->ram_mask; udb_ptr* p, *np; /* edit them and move them into the new position */ p = udb->ram_hash[io]; while(p) { np = p->next; if(p->data == old) { udb_base_unlink_ptr(udb, p); p->data = newd; udb_base_link_ptr(udb, p); } p = np; } } udb_rel_ptr* udb_base_get_userdata(udb_base* udb) { return &udb->glob_data->user_global; } void udb_base_set_userdata(udb_base* udb, udb_void user) { #ifdef UDB_CHECK if(user) { assert(udb_valid_dataptr(udb, user)); } #endif udb_rel_ptr_set(udb->base, &udb->glob_data->user_global, user); } void udb_base_set_userflags(udb_base* udb, uint8_t v) { udb->glob_data->userflags = v; } uint8_t udb_base_get_userflags(udb_base* udb) { return udb->glob_data->userflags; } /** re-mmap the udb to specified size */ static void* udb_base_remap(udb_base* udb, udb_alloc* alloc, uint64_t nsize) { #ifdef HAVE_MMAP void* nb; /* for use with valgrind, do not use mremap, but the other version */ #ifdef MREMAP_MAYMOVE nb = mremap(udb->base, udb->base_size, nsize, MREMAP_MAYMOVE); if(nb == MAP_FAILED) { log_msg(LOG_ERR, "mremap(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); return 0; } #else /* !HAVE MREMAP */ /* use munmap-mmap to simulate mremap */ if(munmap(udb->base, udb->base_size) != 0) { log_msg(LOG_ERR, "munmap(%s) error %s", udb->fname, strerror(errno)); } /* provide hint for new location */ /* note the size_t casts must be there for portability, on some * systems the layout of memory is otherwise broken. */ nb = mmap(udb->base, (size_t)nsize, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); /* retry the mmap without basept in case of ENOMEM (FreeBSD8), * the kernel can then try to mmap it at a different location * where more memory is available */ if(nb == MAP_FAILED && errno == ENOMEM) { nb = mmap(NULL, (size_t)nsize, (int)PROT_READ|PROT_WRITE, (int)MAP_SHARED, (int)udb->fd, (off_t)0); } if(nb == MAP_FAILED) { log_msg(LOG_ERR, "mmap(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); udb->base = NULL; return 0; } #endif /* HAVE MREMAP */ if(nb != udb->base) { /* fix up realpointers in udb and alloc */ /* but mremap may have been nice and not move the base */ udb->base = nb; udb->glob_data = (udb_glob_d*)(nb+sizeof(uint64_t)); /* use passed alloc pointer because the udb->alloc may not * be initialized yet */ alloc->disk = (udb_alloc_d*)((void*)udb->glob_data +sizeof(*udb->glob_data)); } udb->base_size = nsize; return nb; #else /* HAVE_MMAP */ (void)udb; (void)alloc; (void)nsize; return NULL; #endif /* HAVE_MMAP */ } void udb_base_remap_process(udb_base* udb) { /* assume that fsize is still accessible */ udb_base_remap(udb, udb->alloc, udb->glob_data->fsize); } /** grow file to specified size and re-mmap, return new base */ static void* udb_base_grow_and_remap(udb_base* udb, uint64_t nsize) { /* grow file by writing a single zero at that spot, the * rest is filled in with zeroes. */ uint8_t z = 0; ssize_t w; assert(nsize > 0); udb->glob_data->dirty_alloc = udb_dirty_fsize; #ifdef HAVE_PWRITE if((w=pwrite(udb->fd, &z, sizeof(z), (off_t)(nsize-1))) == -1) { #else if(lseek(udb->fd, (off_t)(nsize-1), SEEK_SET) == -1) { log_msg(LOG_ERR, "fseek %s: %s", udb->fname, strerror(errno)); return 0; } if((w=write(udb->fd, &z, sizeof(z))) == -1) { #endif log_msg(LOG_ERR, "grow(%s, size %u) error %s", udb->fname, (unsigned)nsize, strerror(errno)); return 0; } else if(w != (ssize_t)sizeof(z)) { log_msg(LOG_ERR, "grow(%s, size %u) failed (disk full?)", udb->fname, (unsigned)nsize); return 0; } udb->glob_data->fsize = nsize; udb->glob_data->dirty_alloc = udb_dirty_clean; return udb_base_remap(udb, udb->alloc, nsize); } int udb_exp_size(uint64_t a) { /* find enclosing value such that 2**x >= a */ int x = 0; uint64_t i = a; assert(a != 0); i --; /* could optimise this with uint8* access, depends on endianness */ /* first whole bytes */ while( (i&(~(uint64_t)0xff)) ) { i >>= 8; x += 8; } /* now details */ while(i) { i >>= 1; x ++; } assert( x>=0 && x<=63); assert( ((uint64_t)1<= a); assert( x==0 || ((uint64_t)1<<(x-1)) < a); return x; } int udb_exp_offset(uint64_t o) { /* this means measuring the number of 0 bits on the right */ /* so, if exp zero bits then (o&(2**x-1))==0 */ int x = 0; uint64_t i = o; assert(o != 0); /* first whole bytes */ while( (i&(uint64_t)0xff) == 0) { i >>= 8; x += 8; } /* now details */ while( (i&(uint64_t)0x1) == 0) { i >>= 1; x ++; } assert( o % ((uint64_t)1<nextgrow = UDB_HEADER_SIZE; } /** fsck the file size, false if failed and file is useless */ static int fsck_fsize(udb_base* udb, udb_alloc* alloc) { off_t realsize; log_msg(LOG_WARNING, "udb-fsck %s: file size wrong", udb->fname); realsize = lseek(udb->fd, (off_t)0, SEEK_END); if(realsize == (off_t)-1) { log_msg(LOG_ERR, "lseek(%s): %s", udb->fname, strerror(errno)); return 0; } udb->glob_data->fsize = (uint64_t)realsize; if(!udb_base_remap(udb, alloc, (uint64_t)realsize)) return 0; udb->glob_data->dirty_alloc = udb_dirty_clean; log_msg(LOG_WARNING, "udb-fsck %s: file size fixed (sync)", udb->fname); udb_base_sync(udb, 1); return 1; } /** regenerate freelist add a new free chunk, return next todo */ static udb_void regen_free(void* base, udb_void c, int exp, udb_alloc_d* regen) { udb_free_chunk_d* cp = UDB_FREE_CHUNK(c); uint64_t esz = (uint64_t)1< UDB_ALLOC_CHUNKS_MAX) { return 0; } cp->type = udb_chunk_type_free; cp->flags = 0; chunk_set_last(base, c, exp, (uint8_t)exp); cp->prev = 0; cp->next = regen->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(cp->next) UDB_FREE_CHUNK(cp->next)->prev = c; regen->stat_free += esz; return c + esz; } /** regenerate xl chunk, return next todo */ static udb_void regen_xl(void* base, udb_void c, udb_alloc_d* regen) { udb_xl_chunk_d* cp = UDB_XL_CHUNK(c); uint64_t xlsz = cp->size; if( (xlsz&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) { return 0; } if( (c&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) { return 0; } /* fixup end-size and end-expmarker */ regen->stat_alloc += xlsz; return c + xlsz; } /** regenerate data chunk, return next todo */ static udb_void regen_data(void* base, udb_void c, int exp, udb_alloc_d* regen) { uint64_t esz = (uint64_t)1< UDB_ALLOC_CHUNKS_MAX) { return 0; } chunk_set_last(base, c, exp, (uint8_t)exp); regen->stat_alloc += esz; return c + esz; } /** regenerate a relptr structure inside a data segment */ static void regen_relptr_func(void* base, udb_rel_ptr* rp, void* arg) { udb_void* a = (udb_void*)arg; /* ignore 0 pointers */ if(!rp->data) return; /* edit relptrs that point to oldmoved to point to newmoved. */ if(rp->data == a[0]) rp->data = a[1]; /* regenerate relptr lists, add this item to the relptr list for * the data that it points to */ udb_rel_ptr_link(base, rp, rp->data); } /** regenerate the relptrs store in this data segment */ static void regen_its_ptrs(void* base, udb_base* udb, udb_chunk_d* atp, void* data, uint64_t dsz, udb_void rb_old, udb_void rb_new) { udb_void arg[2]; arg[0] = rb_old; arg[1] = rb_new; /* walk through the structs here and put them on their respective * relptr lists */ (*udb->walkfunc)(base, udb->walkarg, atp->type, data, dsz, ®en_relptr_func, arg); } /** regenerate relptrlists in the file */ static void regen_ptrlist(void* base, udb_base* udb, udb_alloc* alloc, udb_void rb_old, udb_void rb_new) { udb_void at = alloc->udb->glob_data->hsize; /* clear all ptrlist start pointers in the file. */ while(at < alloc->disk->nextgrow) { int exp = (int)UDB_CHUNK(at)->exp; udb_chunk_type tp = (udb_chunk_type)UDB_CHUNK(at)->type; if(exp == UDB_EXP_XL) { UDB_XL_CHUNK(at)->ptrlist = 0; at += UDB_XL_CHUNK(at)->size; } else if(tp == udb_chunk_type_free) { at += (uint64_t)1<ptrlist = 0; at += (uint64_t)1<udb->glob_data->hsize; while(at < alloc->disk->nextgrow) { udb_chunk_d* atp = UDB_CHUNK(at); int exp = (int)atp->exp; udb_chunk_type tp = (udb_chunk_type)atp->type; uint64_t sz = ((exp == UDB_EXP_XL)?UDB_XL_CHUNK(at)->size: (uint64_t)1<= UDB_ALLOC_CHUNK_SIZE*/ assert(s >= UDB_ALLOC_CHUNK_SIZE); while(q >= s) { UDB_CHUNK(q)->exp = UDB_ALLOC_CHUNKS_MAX; UDB_CHUNK(q)->type = udb_chunk_type_free; q -= UDB_ALLOC_CHUNK_SIZE; } } /** fsck rollback or rollforward XL move results */ static int fsck_rb_xl(void* base, udb_base* udb, udb_void rb_old, udb_void rb_new, uint64_t rb_size, uint64_t rb_seg) { if(rb_old <= rb_new) return 0; /* XL move one way */ if( (rb_size&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if( (rb_old&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if( (rb_new&(UDB_ALLOC_CHUNK_SIZE-1)) != 0) return 0; /* not aligned */ if(rb_new + rb_size <= rb_old) { /* not overlapping: resume copy */ memcpy(UDB_CHUNK(rb_new), UDB_CHUNK(rb_old), rb_size); /* and free up old piece(s) */ rb_mark_free_segs(base, rb_old, rb_size); } else { /* overlapping, see what segment we stopped at * and continue there. */ move_xl_segment(base, udb, rb_old, rb_new, rb_size, rb_seg); /* free up old piece(s); from the end of the moved segment, * until the end of the old segment */ rb_mark_free_segs(base, rb_new+rb_size, (rb_old+rb_size)- (rb_new+rb_size)); } /* do not call fix_ptrs, regenptrs does the job */ return 1; } /** fsck rollback or rollforward move results */ static int fsck_rb(void* base, udb_void rb_old, udb_void rb_new, uint64_t rb_size, udb_void* make_free) { if( (rb_size&(rb_size-1)) != 0) return 0; /* not powerof2 */ if( (rb_old&(rb_size-1)) != 0) return 0; /* not aligned */ if( (rb_new&(rb_size-1)) != 0) return 0; /* not aligned */ /* resume copy */ memcpy(UDB_CHUNK(rb_new), UDB_CHUNK(rb_old), rb_size); /* do not call fix_ptrs, regenptrs does the job */ /* make sure udb_old is freed */ *make_free = rb_old; return 1; } /** fsck the file and salvage, false if failed and file is useless */ static int fsck_file(udb_base* udb, udb_alloc* alloc, int moved) { void* base = udb->base; udb_alloc_d regen; udb_void at = udb->glob_data->hsize; udb_void rb_old = udb->glob_data->rb_old; udb_void rb_new = udb->glob_data->rb_new; udb_void rb_seg = udb->glob_data->rb_seg; udb_void make_free = 0; uint64_t rb_size = udb->glob_data->rb_size; log_msg(LOG_WARNING, "udb-fsck %s: salvaging", udb->fname); /* walk through the file, use the exp values to see what can be * salvaged */ if(moved && rb_old && rb_new && rb_size) { if(rb_old+rb_size <= alloc->disk->nextgrow && rb_new+rb_size <= alloc->disk->nextgrow) { /* we can use the move information to fix up the * duplicate element (or partially moved element) */ if(rb_size > 1024*1024) { /* XL chunk */ if(!fsck_rb_xl(base, udb, rb_old, rb_new, rb_size, rb_seg)) return 0; } else { if(!fsck_rb(base, rb_old, rb_new, rb_size, &make_free)) return 0; } } } /* rebuild freelists */ /* recalculate stats in alloc (except 'stat_data') */ /* possibly new end 'nextgrow' value */ memset(®en, 0, sizeof(regen)); regen.nextgrow = alloc->disk->nextgrow; while(at < regen.nextgrow) { /* figure out this chunk */ int exp = (int)UDB_CHUNK(at)->exp; udb_chunk_type tp = (udb_chunk_type)UDB_CHUNK(at)->type; /* consistency check possible here with end-exp */ if(tp == udb_chunk_type_free || at == make_free) { at = regen_free(base, at, exp, ®en); if(!at) return 0; } else if(exp == UDB_EXP_XL) { /* allocated data of XL size */ at = regen_xl(base, at, ®en); if(!at) return 0; } else if(exp >= UDB_ALLOC_CHUNK_MINEXP && exp <= UDB_ALLOC_CHUNKS_MAX) { /* allocated data */ at = regen_data(base, at, exp, ®en); if(!at) return 0; } else { /* garbage; this must be EOF then */ regen.nextgrow = at; break; } } *alloc->disk = regen; /* rebuild relptr lists */ regen_ptrlist(base, udb, alloc, rb_old, rb_new); log_msg(LOG_WARNING, "udb-fsck %s: salvaged successfully (sync)", udb->fname); udb->glob_data->rb_old = 0; udb->glob_data->rb_new = 0; udb->glob_data->rb_size = 0; udb->glob_data->dirty_alloc = udb_dirty_clean; udb_base_sync(udb, 1); return 1; } udb_alloc* udb_alloc_create(udb_base* udb, udb_alloc_d* disk) { udb_alloc* alloc = (udb_alloc*)xalloc_zero(sizeof(*alloc)); if(!alloc) return NULL; alloc->udb = udb; alloc->disk = disk; /* see if committed but uncompleted actions need to be done */ /* preserves the alloc state */ if(udb->glob_data->dirty_alloc != udb_dirty_clean) { if(udb->glob_data->dirty_alloc == udb_dirty_fsize) { if(fsck_fsize(udb, alloc)) return alloc; } else if(udb->glob_data->dirty_alloc == udb_dirty_fl) { if(fsck_file(udb, alloc, 0)) return alloc; } else if(udb->glob_data->dirty_alloc == udb_dirty_compact) { if(fsck_file(udb, alloc, 1)) return alloc; } log_msg(LOG_ERR, "error: file allocation dirty (%d)", (int)udb->glob_data->dirty_alloc); free(alloc); return NULL; } return alloc; } void udb_alloc_delete(udb_alloc* alloc) { if(!alloc) return; free(alloc); } /** unlink this element from its freelist */ static void udb_alloc_unlink_fl(void* base, udb_alloc* alloc, udb_void chunk, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(chunk); assert(chunk); /* chunk is a free chunk */ assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, chunk, exp) == (uint8_t)exp); /* and thus freelist not empty */ assert(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]); /* unlink */ if(fp->prev) UDB_FREE_CHUNK(fp->prev)->next = fp->next; else alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = fp->next; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = fp->prev; } /** pop first element off freelist, list may not be empty */ static udb_void udb_alloc_pop_fl(void* base, udb_alloc* alloc, int exp) { udb_void f = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, f, exp) == (uint8_t)exp); alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = fp->next; if(fp->next) { UDB_FREE_CHUNK(fp->next)->prev = 0; } return f; } /** push new element onto freelist */ static void udb_alloc_push_fl(void* base, udb_alloc* alloc, udb_void f, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); fp->exp = (uint8_t)exp; fp->type = udb_chunk_type_free; fp->flags = 0; fp->prev = 0; fp->next = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = f; chunk_set_last(base, f, exp, (uint8_t)exp); alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = f; } /** push new element onto freelist - do not initialize the elt */ static void udb_alloc_push_fl_noinit(void* base, udb_alloc* alloc, udb_void f, int exp) { udb_free_chunk_d* fp = UDB_FREE_CHUNK(f); assert(f); assert(fp->exp == (uint8_t)exp); assert(fp->type == udb_chunk_type_free); assert(chunk_get_last(base, f, exp) == (uint8_t)exp); fp->prev = 0; fp->next = alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]; if(fp->next) UDB_FREE_CHUNK(fp->next)->prev = f; alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP] = f; } /** add free chunks at end until specified alignment occurs */ static void grow_align(void* base, udb_alloc* alloc, uint64_t esz) { while( (alloc->disk->nextgrow & (esz-1)) != 0) { /* the nextgrow is not a whole multiple of esz. */ /* grow a free chunk of max allowed size */ int fexp = udb_exp_offset(alloc->disk->nextgrow); uint64_t fsz = (uint64_t)1<disk->nextgrow; udb_void fn = alloc->disk->nextgrow+fsz; assert(fn <= alloc->udb->base_size); alloc->disk->stat_free += fsz; udb_alloc_push_fl(base, alloc, f, fexp); /* now increase nextgrow to commit that free chunk */ alloc->disk->nextgrow = fn; } } /** append chunks at end of memory space to get size exp, return dataptr */ static udb_void grow_chunks(void* base, udb_alloc* alloc, size_t sz, int exp) { uint64_t esz = (uint64_t)1<udb->glob_data->dirty_alloc = udb_dirty_fl; grow_align(base, alloc, esz); /* free chunks are grown, grow the one we want to use */ ret = alloc->disk->nextgrow; /* take a new alloced chunk into use */ UDB_CHUNK(ret)->exp = (uint8_t)exp; UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; UDB_CHUNK(ret)->type = udb_chunk_type_data; /* store last octet */ chunk_set_last(base, ret, exp, (uint8_t)exp); /* update stats */ alloc->disk->stat_alloc += esz; alloc->disk->stat_data += sz; /* now increase nextgrow to commit this newly allocated chunk */ alloc->disk->nextgrow += esz; assert(alloc->disk->nextgrow <= alloc->udb->base_size); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /** calculate how much space is necessary to grow for this exp */ static uint64_t grow_end_calc(udb_alloc* alloc, int exp) { uint64_t sz = (uint64_t)1<disk->nextgrow; uint64_t res; /* if nextgrow is 2**expness, no extra growth needed, only size */ if( (ng & (sz-1)) == 0) { /* sz-1 is like 0xfff, and checks if ng is whole 2**exp */ return ng+sz; /* must grow exactly 2**exp */ } /* grow until 2**expness and then we need 2**exp as well */ /* so, round ng down to whole sz (basically ng-ng%sz, or ng/sz*sz) * and then add the sz twice (go up to whole sz, and to allocate) */ res = (ng & ~(sz-1)) + 2*sz; return res; } /** see if we need to grow more than specified to enable sustained growth */ static uint64_t grow_extra_check(udb_alloc* alloc, uint64_t ge) { const uint64_t mb = 1024*1024; uint64_t bsz = alloc->udb->base_size; if(bsz <= mb) { /* below 1 Mb, double sizes for exponential growth */ /* takes about 15 times to grow to 1Mb */ if(ge < bsz*2) return bsz*2; } else { uint64_t gnow = ge - bsz; /* above 1Mb, grow at least 1 Mb, or 12.5% of current size, * in whole megabytes rounded up. */ uint64_t want = ((bsz / 8) & ~(mb-1)) + mb; if(gnow < want) return bsz + want; } return ge; } /** see if free space is enogh to warrant shrink (while file is open) */ static int enough_free(udb_alloc* alloc) { if(alloc->udb->base_size <= 2*1024*1024) { /* below 1 Mb, grown by double size, (so up to 2 mb), * do not shrink unless we can 1/3 in size */ if(((size_t)alloc->disk->nextgrow)*3 <= alloc->udb->base_size) return 1; } else { /* grown 12.5%, shrink 25% if possible, at least one mb */ /* between 1mb and 4mb size, it shrinks by 1mb if possible */ uint64_t space = alloc->udb->base_size - alloc->disk->nextgrow; if(space >= 1024*1024 && (space*4 >= alloc->udb->base_size || alloc->udb->base_size < 4*1024*1024)) return 1; } return 0; } /** grow space for a chunk of 2**exp and return dataptr */ static udb_void udb_alloc_grow_space(void* base, udb_alloc* alloc, size_t sz, int exp) { /* commit the grow action * - the file grow only changes filesize, but not the nextgrow. * - taking space after nextgrow into use (as free space), * is like free-ing a chunk (one at a time). * - and the last chunk taken into use is like alloc. */ /* predict how much free space is needed for this */ uint64_t grow_end = grow_end_calc(alloc, exp); assert(alloc->udb->base_size >= alloc->disk->nextgrow); if(grow_end <= alloc->udb->base_size) { /* we can do this with the available space */ return grow_chunks(base, alloc, sz, exp); } /* we have to grow the file, re-mmap */ /* see if we need to grow a little more, to avoid endless grow * efforts on adding data */ grow_end = grow_extra_check(alloc, grow_end); if(!(base=udb_base_grow_and_remap(alloc->udb, grow_end))) { return 0; /* mmap or write failed (disk or mem full) */ } /* we have enough space now */ assert(grow_end <= alloc->udb->base_size); assert(alloc->udb->glob_data->fsize == alloc->udb->base_size); return grow_chunks(base, alloc, sz, exp); } /** take XL allocation into use at end of file, return dataptr */ static udb_void grow_xl(void* base, udb_alloc* alloc, uint64_t xlsz, uint64_t sz) { udb_void ret; udb_xl_chunk_d* p; alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; /* align growth to whole mbs */ grow_align(base, alloc, UDB_ALLOC_CHUNK_SIZE); /* grow XL segment */ ret = alloc->disk->nextgrow; p = UDB_XL_CHUNK(ret); p->exp = UDB_EXP_XL; p->size = xlsz; p->flags = 0; p->ptrlist = 0; p->type = udb_chunk_type_data; /* also put size and marker at end for compaction */ *((uint64_t*)(UDB_REL(base, ret+xlsz-sizeof(uint64_t)*2))) = xlsz; *((uint8_t*)(UDB_REL(base, ret+xlsz-1))) = UDB_EXP_XL; /* stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += xlsz; /* now increase the nextgrow to commit this xl chunk */ alloc->disk->nextgrow += xlsz; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_xl_chunk_d); /* data ptr */ } /** make space for XL allocation */ static udb_void udb_alloc_xl_space(void* base, udb_alloc* alloc, size_t sz) { /* allocate whole mbs of space, at end of space */ uint64_t asz = sz + sizeof(udb_xl_chunk_d) + sizeof(uint64_t)*2; uint64_t need=(asz+UDB_ALLOC_CHUNK_SIZE-1)&(~(UDB_ALLOC_CHUNK_SIZE-1)); uint64_t grow_end = grow_end_calc(alloc, UDB_ALLOC_CHUNKS_MAX) + need; assert(need >= asz); if(grow_end <= alloc->udb->base_size) { /* can do this in available space */ return grow_xl(base, alloc, need, sz); } /* have to grow file and re-mmap */ grow_end = grow_extra_check(alloc, grow_end); if(!(base=udb_base_grow_and_remap(alloc->udb, grow_end))) { return 0; /* mmap or write failed (disk or mem full) */ } /* we have enough space now */ assert(grow_end <= alloc->udb->base_size); assert(alloc->udb->glob_data->fsize == alloc->udb->base_size); return grow_xl(base, alloc, need, sz); } /** divide big(2**e2) into pieces so 2**exp fits */ static udb_void udb_alloc_subdivide(void* base, udb_alloc* alloc, udb_void big, int e2, int exp) { int e = e2; uint64_t sz = (uint64_t)1< exp); /* so the returned piece to use is the first piece, * offload the later half until it fits */ do { sz >>= 1; /* divide size of big by two */ e--; /* that means its exp is one smaller */ udb_alloc_push_fl(base, alloc, big+sz, e); } while(e != exp); /* exit loop when last pushed is same size as what we want */ return big; } /** returns the exponent size of the chunk needed for data sz */ static int udb_alloc_exp_needed(size_t sz) { uint64_t asz = sz + sizeof(udb_chunk_d) + 1; if(asz > UDB_ALLOC_CHUNK_SIZE) { return UDB_EXP_XL; } else if(asz <= UDB_ALLOC_CHUNK_MINSIZE) { return UDB_ALLOC_CHUNK_MINEXP; } return udb_exp_size(asz); } udb_void udb_alloc_space(udb_alloc* alloc, size_t sz) { void* base = alloc->udb->base; /* calculate actual allocation size */ int e2, exp = udb_alloc_exp_needed(sz); if(exp == UDB_EXP_XL) return udb_alloc_xl_space(base, alloc, sz); /* see if there is a free chunk of that size exactly */ if(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]) { /* snip from freelist, udb_chunk_d */ udb_void ret; alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; ret = udb_alloc_pop_fl(base, alloc, exp); /* use it - size octets already OK */ UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; UDB_CHUNK(ret)->type = udb_chunk_type_data; /* update stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += (1<disk->stat_free >= (1u<disk->stat_free -= (1<udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /* see if we can subdivide a larger chunk */ for(e2 = exp+1; e2 <= UDB_ALLOC_CHUNKS_MAX; e2++) if(alloc->disk->free[e2-UDB_ALLOC_CHUNK_MINEXP]) { udb_void big, ret; /* udb_chunk_d */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; big = udb_alloc_pop_fl(base, alloc, e2); /* push other parts onto freelists (needs inited) */ ret = udb_alloc_subdivide(base, alloc, big, e2, exp); /* use final part (needs inited) */ UDB_CHUNK(ret)->exp = (uint8_t)exp; /* if stop here; the new exp makes smaller free chunk*/ UDB_CHUNK(ret)->flags = 0; UDB_CHUNK(ret)->ptrlist = 0; /* set type to commit data chunk */ UDB_CHUNK(ret)->type = udb_chunk_type_data; /* store last octet */ chunk_set_last(base, ret, exp, (uint8_t)exp); /* update stats */ alloc->disk->stat_data += sz; alloc->disk->stat_alloc += (1<disk->stat_free >= (1u<disk->stat_free -= (1<udb->glob_data->dirty_alloc = udb_dirty_clean; return ret + sizeof(udb_chunk_d); /* ptr to data */ } /* we need to grow an extra chunk */ return udb_alloc_grow_space(base, alloc, sz, exp); } /** see if there is free space to allocate a chunk into */ static int have_free_for(udb_alloc* alloc, int exp) { int e2; if(alloc->disk->free[exp-UDB_ALLOC_CHUNK_MINEXP]) return exp; for(e2 = exp+1; e2 <= UDB_ALLOC_CHUNKS_MAX; e2++) if(alloc->disk->free[e2-UDB_ALLOC_CHUNK_MINEXP]) { return e2; } return 0; } /** fix relptr prev and next for moved relptr structures */ static void chunk_fix_ptr_each(void* base, udb_rel_ptr* rp, void* arg) { udb_void* data = (udb_void*)arg; udb_void r; if(!rp->data) return; r = UDB_SYSTOREL(base, rp); if(rp->next) UDB_REL_PTR(rp->next)->prev = r; if(rp->prev) UDB_REL_PTR(rp->prev)->next = r; else { /* if this is a pointer to its own chunk, fix it up; * the data ptr gets set by relptr_edit later. */ if(rp->data == data[0]) UDB_CHUNK(data[1])->ptrlist = r; else UDB_CHUNK(chunk_from_dataptr(rp->data))->ptrlist = r; } } /** fix pointers from and to a moved chunk */ static void chunk_fix_ptrs(void* base, udb_base* udb, udb_chunk_d* cp, udb_void data, uint64_t dsz, udb_void olddata) { udb_void d[2]; d[0] = olddata; d[1] = data; (*udb->walkfunc)(base, udb->walkarg, cp->type, UDB_REL(base, data), dsz, &chunk_fix_ptr_each, d); udb_rel_ptr_edit(base, cp->ptrlist, data); udb_base_ram_ptr_edit(udb, olddata, data); } /** move an allocated chunk to use a free chunk */ static void move_chunk(void* base, udb_alloc* alloc, udb_void f, int exp, uint64_t esz, int e2) { udb_void res = udb_alloc_pop_fl(base, alloc, e2); udb_chunk_d* rp; udb_chunk_d* fp; if(exp != e2) { /* it is bigger, subdivide it */ res = udb_alloc_subdivide(base, alloc, res, e2, exp); } assert(res != f); /* setup rollback information */ alloc->udb->glob_data->rb_old = f; alloc->udb->glob_data->rb_new = res; alloc->udb->glob_data->rb_size = esz; /* take the res, exp into use */ rp = UDB_CHUNK(res); fp = UDB_CHUNK(f); /* copy over the data */ memcpy(rp, fp, esz); /* adjust rel ptrs */ chunk_fix_ptrs(base, alloc->udb, rp, res+sizeof(udb_chunk_d), esz-sizeof(udb_chunk_d)-1, f+sizeof(udb_chunk_d)); /* do not freeup the fp; caller does that */ } /** unlink several free elements to overwrite with xl chunk */ static void free_xl_space(void* base, udb_alloc* alloc, udb_void s, uint64_t m) { udb_void q = s + m - UDB_ALLOC_CHUNK_SIZE; /* because of header and alignment we know s >= UDB_ALLOC_CHUNK_SIZE*/ assert(s >= UDB_ALLOC_CHUNK_SIZE); while(q >= s) { assert(UDB_CHUNK(q)->exp == UDB_ALLOC_CHUNKS_MAX); assert(UDB_CHUNK(q)->type == udb_chunk_type_free); udb_alloc_unlink_fl(base, alloc, q, UDB_ALLOC_CHUNKS_MAX); q -= UDB_ALLOC_CHUNK_SIZE; } } /** move an XL chunk, and keep track of segments for rollback */ static void move_xl_segment(void* base, udb_base* udb, udb_void xl, udb_void n, uint64_t sz, uint64_t startseg) { udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); udb_xl_chunk_d* np = UDB_XL_CHUNK(n); uint64_t amount = xl - n; assert(n < xl); /* move to compact */ /* setup move rollback */ udb->glob_data->rb_old = xl; udb->glob_data->rb_new = n; udb->glob_data->rb_size = sz; /* is it overlapping? */ if(sz <= amount) { memcpy(np, xlp, sz); } else { /* move and commit per 1M segment to avoid data loss */ uint64_t seg, maxseg = amount/UDB_ALLOC_CHUNK_SIZE; for(seg = startseg; segglob_data->rb_seg = seg; memcpy(np+seg*UDB_ALLOC_CHUNK_SIZE, xlp+seg*UDB_ALLOC_CHUNK_SIZE, UDB_ALLOC_CHUNK_SIZE); } } } /** move list of XL chunks to the front by the shift amount */ static void move_xl_list(void* base, udb_alloc* alloc, udb_void xl_start, uint64_t xl_sz, uint64_t amount) { udb_void xl = xl_start; assert( (xl_start&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* aligned */ assert( (amount&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* multiples */ assert( (xl_sz&(UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* multiples */ while(xl < xl_start+xl_sz) { udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); udb_void n = xl-amount; uint64_t sz = xlp->size; assert(xlp->exp == UDB_EXP_XL); move_xl_segment(base, alloc->udb, xl, n, sz, 0); chunk_fix_ptrs(base, alloc->udb, UDB_CHUNK(n), n+sizeof(udb_xl_chunk_d), sz-sizeof(udb_xl_chunk_d)-sizeof(uint64_t)*2, xl+sizeof(udb_xl_chunk_d)); } alloc->disk->stat_free -= amount; alloc->disk->nextgrow -= amount; alloc->udb->glob_data->rb_old = 0; alloc->udb->glob_data->rb_new = 0; alloc->udb->glob_data->rb_size = 0; } /** see if free chunk can coagulate with another chunk, return other chunk */ static udb_void coagulate_possible(void* base, udb_alloc* alloc, udb_void f, int exp, uint64_t esz) { udb_void other = f^esz; if(exp == UDB_ALLOC_CHUNKS_MAX) return 0; /* no further merges */ if(other >= alloc->udb->base_size) return 0; /* not allocated */ if(other >= alloc->disk->nextgrow) return 0; /* not in use */ if(other < alloc->udb->glob_data->hsize) return 0; /* cannot merge with header */ /* the header is also protected by the special exp marker */ /* see if the other chunk is a free chunk */ /* check closest marker to avoid large memory churn */ /* and also it makes XL allocations and header special markers work */ if(f > other) { assert(f > 1); /* this is certain because of header */ if(*((uint8_t*)UDB_REL(base, f-1)) == (uint8_t)exp) { /* can do it if the other part is a free chunk */ assert(UDB_FREE_CHUNK(other)->exp == (uint8_t)exp); if(UDB_CHUNK(other)->type == udb_chunk_type_free) return other; } } else { if(UDB_CHUNK(other)->exp == (uint8_t)exp) { /* can do it if the other part is a free chunk */ assert(chunk_get_last(base, other, exp)==(uint8_t)exp); if(UDB_CHUNK(other)->type == udb_chunk_type_free) return other; } } return 0; } /** coagulate and then add new free segment, return final free segment */ static udb_void coagulate_and_push(void* base, udb_alloc* alloc, udb_void last, int exp, uint64_t esz) { /* new free chunk here, attempt coagulate */ udb_void other; while( (other=coagulate_possible(base, alloc, last, exp, esz)) ) { /* unlink that other chunk */ udb_alloc_unlink_fl(base, alloc, other, exp); /* merge up */ if(other < last) last = other; exp++; esz <<= 1; } /* free the final segment */ udb_alloc_push_fl(base, alloc, last, exp); return last; } /** attempt to compact the data and move free space to the end */ int udb_alloc_compact(void* base, udb_alloc* alloc) { udb_void last; int exp, e2; uint64_t esz; uint64_t at = alloc->disk->nextgrow; udb_void xl_start = 0; uint64_t xl_sz = 0; if(alloc->udb->inhibit_compact) return 1; alloc->udb->useful_compact = 0; while(at > alloc->udb->glob_data->hsize) { /* grab last entry */ exp = (int)*((uint8_t*)UDB_REL(base, at-1)); if(exp == UDB_EXP_XL) { /* for XL chunks: * - inspect the size of the XLchunklist at end * - attempt to compact in front of of XLchunklist */ uint64_t xlsz = *((uint64_t*)UDB_REL(base, at-sizeof(uint64_t)*2)); udb_void xl = at-xlsz; #ifndef NDEBUG udb_xl_chunk_d* xlp = UDB_XL_CHUNK(xl); assert(xlp->exp == UDB_EXP_XL); assert(xlp->type != udb_chunk_type_free); #endif /* got thesegment add to the xl chunk list */ if(xl_start != 0 && xl+xlsz != xl_start) { /* nonadjoining XL part, but they are aligned, * so the space in between is whole Mbs, * shift the later part(s) and continue */ uint64_t m = xl_start - (xl+xlsz); assert(xl_start > xl+xlsz); alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; free_xl_space(base, alloc, xl+xlsz, m); move_xl_list(base, alloc, xl_start, xl_sz, m); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } xl_start = xl; xl_sz += xlsz; at = xl; continue; /* end of XL if */ } else if(exp < UDB_ALLOC_CHUNK_MINEXP || exp > UDB_ALLOC_CHUNKS_MAX) break; /* special chunk or garbage */ esz = (uint64_t)1<exp == (uint8_t)exp); if(UDB_CHUNK(last)->type == udb_chunk_type_free) { /* if xlstart continue looking to move stuff, but do * not unlink this free segment */ if(!xl_start) { /* it is a free chunk, remove it */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; udb_alloc_unlink_fl(base, alloc, last, exp); alloc->disk->stat_free -= esz; alloc->disk->nextgrow = last; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* and continue at this point */ } at = last; } else if( (e2=have_free_for(alloc, exp)) ) { /* last entry can be allocated in free chunks * move it to its new position, adjust rel_ptrs */ alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; move_chunk(base, alloc, last, exp, esz, e2); if(xl_start) { last = coagulate_and_push(base, alloc, last, exp, esz); } else { /* shorten usage */ alloc->disk->stat_free -= esz; alloc->disk->nextgrow = last; } alloc->udb->glob_data->rb_old = 0; alloc->udb->glob_data->rb_new = 0; alloc->udb->glob_data->rb_size = 0; alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* and continue in front of it */ at = last; } else { /* cannot compact this block, stop compacting */ break; } /* if that worked, repeat it */ } /* if we passed xl chunks, see if XL-chunklist can move */ if(xl_start) { /* calculate free space in front of the XLchunklist. */ /* has to be whole mbs of free space */ /* if so, we can move the XL chunks. Move them all back * by the new free space. */ /* this compacts very well, but the XL chunks can be moved * multiple times; worst case for every mb freed a huge sized * xlchunklist gets moved. */ /* free space must be, since aligned and coagulated, in * chunks of a whole MB */ udb_void at = xl_start; uint64_t m = 0; while(*((uint8_t*)UDB_REL(base, at-1))==UDB_ALLOC_CHUNKS_MAX){ udb_void chunk = at - UDB_ALLOC_CHUNK_SIZE; if(UDB_CHUNK(chunk)->type != udb_chunk_type_free) break; assert(UDB_CHUNK(chunk)->exp==UDB_ALLOC_CHUNKS_MAX); m += UDB_ALLOC_CHUNK_SIZE; at = chunk; } if(m != 0) { assert(at+m == xl_start); alloc->udb->glob_data->dirty_alloc = udb_dirty_compact; free_xl_space(base, alloc, at, m); move_xl_list(base, alloc, xl_start, xl_sz, m); alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } } /* if enough free, shrink the file; re-mmap */ if(enough_free(alloc)) { uint64_t nsize = alloc->disk->nextgrow; udb_base_shrink(alloc->udb, nsize); if(!udb_base_remap(alloc->udb, alloc, nsize)) return 0; } return 1; } int udb_compact(udb_base* udb) { if(!udb) return 1; if(!udb->useful_compact) return 1; DEBUG(DEBUG_DBACCESS, 1, (LOG_INFO, "Compacting database...")); return udb_alloc_compact(udb->base, udb->alloc); } void udb_compact_inhibited(udb_base* udb, int inhibit) { if(!udb) return; udb->inhibit_compact = inhibit; } #ifdef UDB_CHECK /** check that rptrs are really zero before free */ void udb_check_rptr_zero(void* base, udb_rel_ptr* p, void* arg) { (void)base; (void)arg; assert(p->data == 0); } #endif /* UDB_CHECK */ /** free XL chunk as multiples of CHUNK_SIZE free segments */ static void udb_free_xl(void* base, udb_alloc* alloc, udb_void f, udb_xl_chunk_d* fp, size_t sz) { uint64_t xlsz = fp->size; uint64_t c; /* lightweight check for buffer overflow in xl data */ assert(*((uint64_t*)(UDB_REL(base, f+xlsz-sizeof(uint64_t)*2)))==xlsz); assert(*((uint8_t*)(UDB_REL(base, f+xlsz-1))) == UDB_EXP_XL); assert( (xlsz & (UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* whole mbs */ assert( (f & (UDB_ALLOC_CHUNK_SIZE-1)) == 0 ); /* aligned */ #ifdef UDB_CHECK /* check that relptrs in this chunk have been zeroed */ (*alloc->udb->walkfunc)(base, alloc->udb->walkarg, fp->type, UDB_REL(base, f+sizeof(udb_xl_chunk_d)), xlsz, &udb_check_rptr_zero, NULL); #endif alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; /* update stats */ alloc->disk->stat_data -= sz; alloc->disk->stat_alloc -= xlsz; alloc->disk->stat_free += xlsz; /* walk in reverse, so the front blocks go first on the list */ c = f + xlsz - UDB_ALLOC_CHUNK_SIZE; /* because of header and alignment we know f >= UDB_ALLOC_CHUNK_SIZE*/ assert(f >= UDB_ALLOC_CHUNK_SIZE); while(c >= f) { /* free a block of CHUNK_SIZE (1 Mb) */ udb_alloc_push_fl(base, alloc, c, UDB_ALLOC_CHUNKS_MAX); c -= UDB_ALLOC_CHUNK_SIZE; } alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; } int udb_alloc_free(udb_alloc* alloc, udb_void r, size_t sz) { void* base; /* lookup chunk ptr */ udb_void f; udb_chunk_d* fp; uint64_t esz; int exp; udb_void other; int coagulated = 0; if(!r) return 1; /* free(NULL) does nothing */ /* lookup size of chunk */ base = alloc->udb->base; /* fails for XL blocks */ f = chunk_from_dataptr(r); fp = UDB_CHUNK(f); assert(fp->type != udb_chunk_type_free); /* see if it has a ptrlist, if so: trouble, the list is not properly * cleaned up. (although you can imagine a wholesale delete where * it does not matter) */ assert(fp->ptrlist == 0); /* set ptrlist to 0 to stop relptr from using it, robustness. */ fp->ptrlist = 0; if(fp->exp == UDB_EXP_XL) { udb_free_xl(base, alloc, f, (udb_xl_chunk_d*)fp, sz); /* compact */ if(alloc->udb->inhibit_compact) { alloc->udb->useful_compact = 1; return 1; } return udb_alloc_compact(base, alloc); } /* it is a regular chunk of 2**exp size */ exp = (int)fp->exp; esz = (uint64_t)1<udb->walkfunc)(base, alloc->udb->walkarg, fp->type, UDB_REL(base, r), esz, &udb_check_rptr_zero, NULL); #endif /* update the stats */ alloc->udb->glob_data->dirty_alloc = udb_dirty_fl; alloc->disk->stat_data -= sz; alloc->disk->stat_free += esz; alloc->disk->stat_alloc -= esz; /* if it can be merged with other free chunks, do so */ while( (other=coagulate_possible(base, alloc, f, exp, esz)) ) { coagulated = 1; /* unlink that other chunk and expand it (it has same size) */ udb_alloc_unlink_fl(base, alloc, other, exp); /* merge up */ if(other < f) f = other; exp++; esz <<= 1; } if(coagulated) { /* put big free chunk into freelist, and init it */ udb_alloc_push_fl(base, alloc, f, exp); } else { /* we do not need to touch the last-exp-byte, which may save * a reference to that page of memory */ fp->type = udb_chunk_type_free; fp->flags = 0; udb_alloc_push_fl_noinit(base, alloc, f, exp); } alloc->udb->glob_data->dirty_alloc = udb_dirty_clean; /* compact */ if(alloc->udb->inhibit_compact) { alloc->udb->useful_compact = 1; return 1; } return udb_alloc_compact(base, alloc); } udb_void udb_alloc_init(udb_alloc* alloc, void* d, size_t sz) { /* could be faster maybe, if grown? */ udb_void r = udb_alloc_space(alloc, sz); if(!r) return r; memcpy(UDB_REL(alloc->udb->base, r), d, sz); return r; } udb_void udb_alloc_realloc(udb_alloc* alloc, udb_void r, size_t osz, size_t sz) { void* base = alloc->udb->base; udb_void c, n, newd; udb_chunk_d* cp, *np; uint64_t avail; uint8_t cp_type; /* emulate some posix realloc stuff */ if(r == 0) return udb_alloc_space(alloc, sz); if(sz == 0) { if(!udb_alloc_free(alloc, r, osz)) log_msg(LOG_ERR, "udb_alloc_realloc: free failed"); return 0; } c = chunk_from_dataptr(r); cp = UDB_CHUNK(c); cp_type = cp->type; if(cp->exp == UDB_EXP_XL) { avail = UDB_XL_CHUNK(c)->size - sizeof(udb_xl_chunk_d) - sizeof(uint64_t)*2; } else { avail = ((uint64_t)1<exp) - sizeof(udb_chunk_d) - 1; } if(sz <= avail) return r; /* reallocate it, and copy */ newd = udb_alloc_space(alloc, sz); if(!newd) return 0; /* re-base after alloc, since re-mmap may have happened */ base = alloc->udb->base; cp = NULL; /* may be invalid now, robustness */ n = chunk_from_dataptr(newd); np = UDB_CHUNK(n); np->type = cp_type; memcpy(UDB_REL(base, newd), UDB_REL(base, r), osz); /* fixup ptrs */ chunk_fix_ptrs(base, alloc->udb, np, newd, osz, r); if(!udb_alloc_free(alloc, r, osz)) log_msg(LOG_ERR, "udb_alloc_realloc: free failed"); return newd; } int udb_alloc_grow(udb_alloc* alloc, size_t sz, size_t num) { const uint64_t mb = 1024*1024; int exp = udb_alloc_exp_needed(sz); uint64_t esz; uint64_t want; if(exp == UDB_EXP_XL) esz = (sz&(mb-1))+mb; else esz = (uint64_t)1<= alloc->udb->base_size); if(!udb_base_grow_and_remap(alloc->udb, want)) { log_msg(LOG_ERR, "failed to grow the specified amount"); return 0; } return 1; } void udb_alloc_set_type(udb_alloc* alloc, udb_void r, udb_chunk_type tp) { void* base = alloc->udb->base; udb_void f = chunk_from_dataptr(r); udb_chunk_d* fp = UDB_CHUNK(f); /* not the 'free' type, that must be set by allocation routines */ assert(fp->type != udb_chunk_type_free); assert(tp != udb_chunk_type_free); fp->type = tp; } int udb_valid_offset(udb_base* udb, udb_void to, size_t destsize) { /* pointers are not valid before the header-size or after the * used-region of the mmap */ return ( (to+destsize) <= udb->base_size && to >= (udb->glob_data->hsize-2*sizeof(udb_rel_ptr)) && (to+destsize) <= udb->alloc->disk->nextgrow); } int udb_valid_dataptr(udb_base* udb, udb_void to) { void* base = udb->base; udb_void ch; int exp; uint64_t esz; /* our data chunks are aligned and at least 8 bytes */ if(!udb_valid_offset(udb, to, sizeof(uint64_t))) return 0; /* get the chunk pointer */ ch = chunk_from_dataptr(to); if(!udb_valid_offset(udb, ch, sizeof(udb_chunk_d))) return 0; /* check its size */ exp = UDB_CHUNK(ch)->exp; if(exp == UDB_EXP_XL) { /* check XL chunk */ uint64_t xlsz; if(!udb_valid_offset(udb, ch, sizeof(udb_xl_chunk_d))) return 0; xlsz = UDB_XL_CHUNK(ch)->size; if(!udb_valid_offset(udb, ch+xlsz-1, 1)) return 0; if(*((uint8_t*)UDB_REL(base, ch+xlsz-1)) != UDB_EXP_XL) return 0; if(*((uint64_t*)UDB_REL(base, ch+xlsz-sizeof(uint64_t)*2)) != xlsz) return 0; return 1; } /* check if regular chunk has matching end byte */ if(exp < UDB_ALLOC_CHUNK_MINEXP || exp > UDB_ALLOC_CHUNKS_MAX) return 0; /* cannot be a valid chunk */ esz = 1<base; udb_void p; if(!udb_valid_offset(udb, rptr, sizeof(udb_rel_ptr))) return 0; if(!udb_valid_dataptr(udb, to)) return 0; p = UDB_CHUNK(chunk_from_dataptr(to))->ptrlist; while(p) { if(!udb_valid_offset(udb, p, sizeof(udb_rel_ptr))) return 0; if(p == rptr) return 1; p = UDB_REL_PTR(p)->next; } return 0; } void udb_rel_ptr_init(udb_rel_ptr* ptr) { memset(ptr, 0, sizeof(*ptr)); } void udb_rel_ptr_unlink(void* base, udb_rel_ptr* ptr) { if(!ptr->data) return; if(ptr->prev) { UDB_REL_PTR(ptr->prev)->next = ptr->next; } else { UDB_CHUNK(chunk_from_dataptr(ptr->data))->ptrlist = ptr->next; } if(ptr->next) { UDB_REL_PTR(ptr->next)->prev = ptr->prev; } } void udb_rel_ptr_link(void* base, udb_rel_ptr* ptr, udb_void to) { udb_chunk_d* chunk = UDB_CHUNK(chunk_from_dataptr(to)); ptr->prev = 0; ptr->next = chunk->ptrlist; if(ptr->next) UDB_REL_PTR(ptr->next)->prev = UDB_SYSTOREL(base, ptr); chunk->ptrlist = UDB_SYSTOREL(base, ptr); ptr->data = to; } void udb_rel_ptr_set(void* base, udb_rel_ptr* ptr, udb_void to) { assert(to == 0 || to > 64); udb_rel_ptr_unlink(base, ptr); if(to) udb_rel_ptr_link(base, ptr, to); else ptr->data = to; } void udb_rel_ptr_edit(void* base, udb_void list, udb_void to) { udb_void p = list; while(p) { UDB_REL_PTR(p)->data = to; p = UDB_REL_PTR(p)->next; } } #ifdef UDB_CHECK /** check that all pointers are validly chained */ static void udb_check_ptrs_valid(udb_base* udb) { size_t i; udb_ptr* p, *prev; for(i=0; iram_size; i++) { prev = NULL; for(p=udb->ram_hash[i]; p; p=p->next) { assert(p->prev == prev); assert((size_t)(chunk_hash_ptr(p->data)&udb->ram_mask) == i); assert(p->base == &udb->base); prev = p; } } } #endif /* UDB_CHECK */ void udb_ptr_init(udb_ptr* ptr, udb_base* udb) { #ifdef UDB_CHECK udb_check_ptrs_valid(udb); /* previous ptrs have been unlinked */ #endif memset(ptr, 0, sizeof(*ptr)); ptr->base = &udb->base; } void udb_ptr_set(udb_ptr* ptr, udb_base* udb, udb_void newval) { assert(newval == 0 || newval > 64); if(ptr->data) udb_base_unlink_ptr(udb, ptr); ptr->data = newval; if(newval) udb_base_link_ptr(udb, ptr); } int udb_ptr_alloc_space(udb_ptr* ptr, udb_base* udb, udb_chunk_type type, size_t sz) { udb_void r; r = udb_alloc_space(udb->alloc, sz); if(!r) return 0; udb_alloc_set_type(udb->alloc, r, type); udb_ptr_init(ptr, udb); udb_ptr_set(ptr, udb, r); return 1; } void udb_ptr_free_space(udb_ptr* ptr, udb_base* udb, size_t sz) { if(ptr->data) { udb_void d = ptr->data; udb_ptr_set(ptr, udb, 0); udb_alloc_free(udb->alloc, d, sz); } } udb_chunk_type udb_ptr_get_type(udb_ptr* ptr) { udb_void f; if(!ptr || ptr->data == 0) return udb_chunk_type_internal; /* something bad*/ f = chunk_from_dataptr(ptr->data); return ((udb_chunk_d*)UDB_REL(*ptr->base, f))->type; } nsd-4.1.26/udbradtree.h0000664000175000017500000002005413040156013014312 0ustar wouterwouter/* * udbradtree -- radix tree for binary strings for in udb file. * * Copyright (c) 2011, NLnet Labs. See LICENSE for license. */ #ifndef UDB_RADTREE_H #define UDB_RADTREE_H #include "udb.h" struct udb_radnode; /** length of the binary string */ typedef uint16_t udb_radstrlen_type; /** * The radix tree * * The elements are stored based on binary strings(0-255) of a given length. * They are sorted, a prefix is sorted before its suffixes. * If you want to know the key string, you should store it yourself, the * tree stores it in the parts necessary for lookup. * For binary strings for domain names see the radname routines. * * This is the tree on disk representation. It has _d suffix in the name * to help delineate disk structures from normal structures. */ struct udb_radtree_d { /** root node in tree, to udb_radnode_d */ struct udb_rel_ptr root; /** count of number of elements */ uint64_t count; }; /** * A radix tree lookup node. It is stored on disk, and the lookup array * is allocated. */ struct udb_radnode_d { /** data element associated with the binary string up to this node */ struct udb_rel_ptr elem; /** parent node (NULL for the root), to udb_radnode_d */ struct udb_rel_ptr parent; /** the array structure, for lookup by [byte-offset]. udb_radarray_d */ struct udb_rel_ptr lookup; /** index in the parent lookup array */ uint8_t pidx; /** offset of the lookup array, add to [i] for lookups */ uint8_t offset; }; /** * radix select edge in array * The string for this element is the Nth string in the stringarray. */ struct udb_radsel_d { /** length of the additional string for this edge, * additional string after the selection-byte for this edge.*/ udb_radstrlen_type len; /** padding for non64bit compilers to 64bit boundaries, to make * the udb file more portable, without this the file would work * on the system it is created on (which is what we promise), but * with this, you have a chance of it working on other platforms */ uint16_t padding16; uint32_t padding32; /** node that deals with byte+str, to udb_radnode_d */ struct udb_rel_ptr node; }; /** * Array of radsel elements. * This is the header, the array is allocated contiguously behind it. * The strings (often very short) are allocated behind the array. * All strings are given the same amount of space (str_cap), * so there is capacity*str_cap bytes at the end. */ struct udb_radarray_d { /** length of the lookup array */ uint16_t len; /** capacity of the lookup array (can be larger than length) */ uint16_t capacity; /** space capacity of for every string */ udb_radstrlen_type str_cap; /** padding to 64bit alignment, just in case compiler goes mad */ uint16_t padding; /** the elements (allocated contiguously after this structure) */ struct udb_radsel_d array[0]; }; /** * Create new radix tree on udb storage * @param udb: the udb to allocate space on. * @param ptr: ptr to the udbradtree is returned here. Pass uninitialised. * type is udb_radtree_d. * @return 0 on alloc failure. */ int udb_radix_tree_create(udb_base* udb, udb_ptr* ptr); /** * Delete intermediate nodes from radix tree * @param udb: the udb. * @param rt: radix tree to be cleared. type udb_radtree_d. */ void udb_radix_tree_clear(udb_base* udb, udb_ptr* rt); /** * Delete radix tree. * You must have deleted the elements, this deletes the nodes. * @param udb: the udb. * @param rt: radix tree to be deleted. type udb_radtree_d. */ void udb_radix_tree_delete(udb_base* udb, udb_ptr* rt); /** * Insert element into radix tree. * @param udb: the udb. * @param rt: the radix tree, type udb_radtree_d. * @param key: key string. * @param len: length of key. * @param elem: pointer to element data, on the udb store. * @param result: the inserted node is set to this value. Pass uninitialised. Not set if the routine fails. * @return NULL on failure - out of memory. * NULL on failure - duplicate entry. * On success the new radix node for this element (udb_radnode_d). */ udb_void udb_radix_insert(udb_base* udb, udb_ptr* rt, uint8_t* k, udb_radstrlen_type len, udb_ptr* elem, udb_ptr* result); /** * Delete element from radix tree. * @param udb: the udb. * @param rt: the radix tree. type udb_radtree_d * @param n: radix node for that element. type udb_radnode_d * if NULL, nothing is deleted. */ void udb_radix_delete(udb_base* udb, udb_ptr* rt, udb_ptr* n); /** * Find radix element in tree. * @param rt: the radix tree, type udb_radtree_d. * @param key: key string. * @param len: length of key. * @return the radix node or NULL if not found. type udb_radnode_d */ udb_void udb_radix_search(udb_ptr* rt, uint8_t* k, udb_radstrlen_type len); /** * Find radix element in tree, and if not found, find the closest smaller or * equal element in the tree. * @param udb: the udb. * @param rt: the radix tree, type udb_radtree_d. * @param key: key string. * @param len: length of key. * @param result: returns the radix node or closest match (NULL if key is * smaller than the smallest key in the tree). type udb_radnode_d. * you can pass an uninitialized ptr, an unlinked or a zeroed one. * @return true if exact match, false if no match. */ int udb_radix_find_less_equal(udb_base* udb, udb_ptr* rt, uint8_t* k, udb_radstrlen_type len, udb_ptr* result); /** * Return the first (smallest) element in the tree. * @param udb: the udb. * @param rt: the radix tree, type udb_radtree_d. * @param p: set to the first node in the tree, or NULL if none. * type udb_radnode_d. * pass uninitialised, zero or unlinked udb_ptr. */ void udb_radix_first(udb_base* udb, udb_ptr* rt, udb_ptr* p); /** * Return the last (largest) element in the tree. * @param udb: the udb. * @param rt: the radix tree, type udb_radtree_d. * @param p: last node or NULL if none, type udb_radnode_d. * pass uninitialised, zero or unlinked udb_ptr. */ void udb_radix_last(udb_base* udb, udb_ptr* rt, udb_ptr* p); /** * Return the next element. * @param udb: the udb. * @param n: adjusted to the next element, or NULL if none. type udb_radnode_d. */ void udb_radix_next(udb_base* udb, udb_ptr* n); /** * Return the previous element. * @param udb: the udb. * @param n: adjusted to the prev node or NULL if none. type udb_radnode_d. */ void udb_radix_prev(udb_base* udb, udb_ptr* n); /* * Perform a walk through all elements of the tree. * node: variable of type struct radnode*. * tree: pointer to the tree. * for(udb_radix_first(tree, node); node->data; udb_radix_next(node)) */ /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radtree */ void udb_radix_tree_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radnode */ void udb_radix_node_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radarray */ void udb_radix_array_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void* arg); /** get the memory used by the lookup structure for a radnode */ size_t size_of_lookup_ext(udb_ptr* node); /** insert radtree element, key is a domain name * @param udb: udb. * @param rt: the tree. * @param dname: domain name in uncompressed wireformat. * @param dlen: length of k. * @param elem: element to store * @param result: the inserted node is set to this value. Pass uninitialised. Not set if the routine fails. * @return 0 on failure */ udb_void udb_radname_insert(udb_base* udb, udb_ptr* rt, const uint8_t* dname, size_t dlen, udb_ptr* elem, udb_ptr* result); /** search for a radname element, key is a domain name. * @param udb: udb * @param rt: the tree * @param dname: domain name in uncompressed wireformat. * @param dlen: length of k. * @param result: result ptr to store the node into. * may be uninitialized. * @return 0 if not found. */ int udb_radname_search(udb_base* udb, udb_ptr* rt, const uint8_t* dname, size_t dlen, udb_ptr* result); #define RADNODE(ptr) ((struct udb_radnode_d*)UDB_PTR(ptr)) #define RADTREE(ptr) ((struct udb_radtree_d*)UDB_PTR(ptr)) #endif /* UDB_RADTREE_H */ nsd-4.1.26/mini_event.h0000664000175000017500000001373613040156013014337 0ustar wouterwouter/* * mini-event.h - micro implementation of libevent api, using select() only. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * This file implements part of the event(3) libevent api. * The back end is only select. Max number of fds is limited. * Max number of signals is limited, one handler per signal only. * And one handler per fd. * * Although limited to select() and a max (1024) open fds, it * is efficient: * o dispatch call caches fd_sets to use. * o handler calling takes time ~ to the number of fds. * o timeouts are stored in a redblack tree, sorted, so take log(n). * Timeouts are only accurate to the second (no subsecond accuracy). * To avoid cpu hogging, fractional timeouts are rounded up to a whole second. */ #ifndef MINI_EVENT_H #define MINI_EVENT_H struct region; #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK) #ifndef HAVE_EVENT_BASE_FREE #define HAVE_EVENT_BASE_FREE #endif /** event timeout */ #define EV_TIMEOUT 0x01 /** event fd readable */ #define EV_READ 0x02 /** event fd writable */ #define EV_WRITE 0x04 /** event signal */ #define EV_SIGNAL 0x08 /** event must persist */ #define EV_PERSIST 0x10 /* needs our redblack tree */ #include "rbtree.h" /** max number of file descriptors to support */ #define MAX_FDS 1024 /** max number of signals to support */ #define MAX_SIG 32 /** event base */ struct event_base { /** sorted by timeout (absolute), ptr */ rbtree_type* times; /** array of 0 - maxfd of ptr to event for it */ struct event** fds; /** max fd in use */ int maxfd; /** capacity - size of the fds array */ int capfd; /* fdset for read write, for fds ready, and added */ fd_set /** fds for reading */ reads, /** fds for writing */ writes, /** fds determined ready for use */ ready, /** ready plus newly added events. */ content; /** array of 0 - maxsig of ptr to event for it */ struct event** signals; /** if we need to exit */ int need_to_exit; /** where to store time in seconds */ time_t* time_secs; /** where to store time in microseconds */ struct timeval* time_tv; /** region for allocation */ struct region* region; }; /** * Event structure. Has some of the event elements. */ struct event { /** node in timeout rbtree */ rbnode_type node; /** is event already added */ int added; /** event base it belongs to */ struct event_base *ev_base; /** fd to poll or -1 for timeouts. signal number for sigs. */ int ev_fd; /** what events this event is interested in, see EV_.. above. */ short ev_flags; /** timeout value */ struct timeval ev_timeout; /** callback to call: fd, eventbits, userarg */ void (*ev_callback)(int, short, void *arg); /** callback user arg */ void *ev_arg; }; /* function prototypes (some are as they appear in event.h) */ /** create event base */ void *event_init(time_t* time_secs, struct timeval* time_tv); /** get version */ const char *event_get_version(void); /** get polling method, select */ const char *event_get_method(void); /** run select in a loop */ int event_base_dispatch(struct event_base *); /** exit that loop */ int event_base_loopexit(struct event_base *, struct timeval *); /** run select once */ #define EVLOOP_ONCE 1 int event_base_loop(struct event_base* base, int flags); /** free event base. Free events yourself */ void event_base_free(struct event_base *); /** set content of event */ void event_set(struct event *, int, short, void (*)(int, short, void *), void *); /** add event to a base. You *must* call this for every event. */ int event_base_set(struct event_base *, struct event *); /** add event to make it active. You may not change it with event_set anymore */ int event_add(struct event *, struct timeval *); /** remove event. You may change it again */ int event_del(struct event *); /** add a timer */ #define evtimer_add(ev, tv) event_add(ev, tv) /** remove a timer */ #define evtimer_del(ev) event_del(ev) /* uses different implementation. Cannot mix fd/timeouts and signals inside * the same struct event. create several event structs for that. */ /** install signal handler */ int signal_add(struct event *, struct timeval *); /** set signal event contents */ #define signal_set(ev, x, cb, arg) \ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) /** remove signal handler */ int signal_del(struct event *); #endif /* USE_MINI_EVENT and not USE_WINSOCK */ /** compare events in tree, based on timevalue, ptr for uniqueness */ int mini_ev_cmp(const void* a, const void* b); #endif /* MINI_EVENT_H */ nsd-4.1.26/axfr.h0000664000175000017500000000103410372122440013130 0ustar wouterwouter/* * axfr.h -- generating AXFR responses. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _AXFR_H_ #define _AXFR_H_ #include "nsd.h" #include "query.h" /* * For optimal compression AXFR response packets are limited in size * to MAX_COMPRESSION_OFFSET. */ #define AXFR_MAX_MESSAGE_LEN MAX_COMPRESSION_OFFSET query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q); query_state_type query_axfr(struct nsd *nsd, struct query *query); #endif /* _AXFR_H_ */ nsd-4.1.26/query.c0000664000175000017500000012711313276267345013363 0ustar wouterwouter/* * query.c -- nsd(8) the resolver. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "answer.h" #include "axfr.h" #include "dns.h" #include "dname.h" #include "nsd.h" #include "namedb.h" #include "query.h" #include "util.h" #include "options.h" #include "nsec3.h" #include "tsig.h" /* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation. * This function determines if the final response packet needs the NS RRset * included. Currently, it will only return negative if QTYPE == DNSKEY|DS. * This way, resolvers won't fallback to TCP unnecessarily when priming * trust anchors. */ static int answer_needs_ns(struct query *query); static int add_rrset(struct query *query, answer_type *answer, rr_section_type section, domain_type *owner, rrset_type *rrset); static void answer_authoritative(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname); static void answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname); void query_put_dname_offset(struct query *q, domain_type *domain, uint16_t offset) { assert(q); assert(domain); assert(domain->number > 0); if (offset > MAX_COMPRESSION_OFFSET) return; if (q->compressed_dname_count >= MAX_COMPRESSED_DNAMES) return; q->compressed_dname_offsets[domain->number] = offset; q->compressed_dnames[q->compressed_dname_count] = domain; ++q->compressed_dname_count; } void query_clear_dname_offsets(struct query *q, size_t max_offset) { while (q->compressed_dname_count > 0 && (q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] >= max_offset)) { q->compressed_dname_offsets[q->compressed_dnames[q->compressed_dname_count - 1]->number] = 0; --q->compressed_dname_count; } } void query_clear_compression_tables(struct query *q) { uint16_t i; for (i = 0; i < q->compressed_dname_count; ++i) { assert(q->compressed_dnames); q->compressed_dname_offsets[q->compressed_dnames[i]->number] = 0; } q->compressed_dname_count = 0; } void query_add_compression_domain(struct query *q, domain_type *domain, uint16_t offset) { while (domain->parent) { DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "query dname: %s, number: %lu, offset: %u\n", domain_to_string(domain), (unsigned long) domain->number, offset)); query_put_dname_offset(q, domain, offset); offset += label_length(dname_name(domain_dname(domain))) + 1; domain = domain->parent; } } /* * Generate an error response with the specified RCODE. */ query_state_type query_error (struct query *q, nsd_rc_type rcode) { if (rcode == NSD_RC_DISCARD) { return QUERY_DISCARDED; } buffer_clear(q->packet); QR_SET(q->packet); /* This is an answer. */ AD_CLR(q->packet); RCODE_SET(q->packet, (int) rcode); /* Error code. */ /* Truncate the question as well... */ QDCOUNT_SET(q->packet, 0); ANCOUNT_SET(q->packet, 0); NSCOUNT_SET(q->packet, 0); ARCOUNT_SET(q->packet, 0); buffer_set_position(q->packet, QHEADERSZ); return QUERY_PROCESSED; } static int query_ratelimit_err(nsd_type* nsd) { time_t now = time(NULL); if(nsd->err_limit_time == now) { /* see if limit is exceeded for this second */ if(nsd->err_limit_count++ > ERROR_RATELIMIT) return 1; } else { /* new second, new limits */ nsd->err_limit_time = now; nsd->err_limit_count = 1; } return 0; } static query_state_type query_formerr (struct query *query, nsd_type* nsd) { int opcode = OPCODE(query->packet); if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; FLAGS_SET(query->packet, FLAGS(query->packet) & 0x0100U); /* Preserve the RD flag. Clear the rest. */ OPCODE_SET(query->packet, opcode); return query_error(query, NSD_RC_FORMAT); } static void query_cleanup(void *data) { query_type *query = (query_type *) data; region_destroy(query->region); } query_type * query_create(region_type *region, uint16_t *compressed_dname_offsets, size_t compressed_dname_size, domain_type **compressed_dnames) { query_type *query = (query_type *) region_alloc_zero(region, sizeof(query_type)); /* create region with large block size, because the initial chunk saves many mallocs in the server */ query->region = region_create_custom(xalloc, free, 16384, 16384/8, 32, 0); query->compressed_dname_offsets = compressed_dname_offsets; query->compressed_dnames = compressed_dnames; query->packet = buffer_create(region, QIOBUFSZ); region_add_cleanup(region, query_cleanup, query); query->compressed_dname_offsets_size = compressed_dname_size; tsig_create_record(&query->tsig, region); query->tsig_prepare_it = 1; query->tsig_update_it = 1; query->tsig_sign_it = 1; return query; } void query_reset(query_type *q, size_t maxlen, int is_tcp) { /* * As long as less than 4Kb (region block size) has been used, * this call to free_all is free, the block is saved for re-use, * so no malloc() or free() calls are done. * at present use of the region is for: * o query qname dname_type (255 max). * o wildcard expansion domain_type (7*ptr+u32+2bytes)+(5*ptr nsec3) * o wildcard expansion for additional section domain_type. * o nsec3 hashed name(s) (3 dnames for a nonexist_proof, * one proof per wildcard and for nx domain). */ region_free_all(q->region); q->addrlen = sizeof(q->addr); q->maxlen = maxlen; q->reserved_space = 0; buffer_clear(q->packet); edns_init_record(&q->edns); tsig_init_record(&q->tsig, NULL, NULL); q->tsig_prepare_it = 1; q->tsig_update_it = 1; q->tsig_sign_it = 1; q->tcp = is_tcp; q->qname = NULL; q->qtype = 0; q->qclass = 0; q->zone = NULL; q->opcode = 0; q->cname_count = 0; q->delegation_domain = NULL; q->delegation_rrset = NULL; q->compressed_dname_count = 0; q->number_temporary_domains = 0; q->axfr_is_done = 0; q->axfr_zone = NULL; q->axfr_current_domain = NULL; q->axfr_current_rrset = NULL; q->axfr_current_rr = 0; #ifdef RATELIMIT q->wildcard_domain = NULL; #endif } /* get a temporary domain number (or 0=failure) */ static domain_type* query_get_tempdomain(struct query *q) { static domain_type d[EXTRA_DOMAIN_NUMBERS]; if(q->number_temporary_domains >= EXTRA_DOMAIN_NUMBERS) return 0; q->number_temporary_domains ++; memset(&d[q->number_temporary_domains-1], 0, sizeof(domain_type)); d[q->number_temporary_domains-1].number = q->compressed_dname_offsets_size + q->number_temporary_domains - 1; return &d[q->number_temporary_domains-1]; } static void query_addtxt(struct query *q, const uint8_t *dname, uint16_t klass, uint32_t ttl, const char *txt) { size_t txt_length = strlen(txt); uint8_t len = (uint8_t) txt_length; assert(txt_length <= UCHAR_MAX); /* Add the dname */ if (dname >= buffer_begin(q->packet) && dname <= buffer_current(q->packet)) { buffer_write_u16(q->packet, 0xc000 | (dname - buffer_begin(q->packet))); } else { buffer_write(q->packet, dname + 1, *dname); } buffer_write_u16(q->packet, TYPE_TXT); buffer_write_u16(q->packet, klass); buffer_write_u32(q->packet, ttl); buffer_write_u16(q->packet, len + 1); buffer_write_u8(q->packet, len); buffer_write(q->packet, txt, len); } /* * Parse the question section of a query. The normalized query name * is stored in QUERY->name, the class in QUERY->klass, and the type * in QUERY->type. */ static int process_query_section(query_type *query) { uint8_t qnamebuf[MAXDOMAINLEN]; buffer_set_position(query->packet, QHEADERSZ); /* Lets parse the query name and convert it to lower case. */ if(!packet_read_query_section(query->packet, qnamebuf, &query->qtype, &query->qclass)) return 0; query->qname = dname_make(query->region, qnamebuf, 1); return 1; } /* * Process an optional EDNS OPT record. Sets QUERY->EDNS to 0 if * there was no EDNS record, to -1 if there was an invalid or * unsupported EDNS record, and to 1 otherwise. Updates QUERY->MAXLEN * if the EDNS record specifies a maximum supported response length. * * Return NSD_RC_FORMAT on failure, NSD_RC_OK on success. */ static nsd_rc_type process_edns(nsd_type* nsd, struct query *q) { if (q->edns.status == EDNS_ERROR) { /* The only error is VERSION not implemented */ return NSD_RC_FORMAT; } if (q->edns.status == EDNS_OK) { /* Only care about UDP size larger than normal... */ if (!q->tcp && q->edns.maxlen > UDP_MAX_MESSAGE_LEN) { size_t edns_size; #if defined(INET6) if (q->addr.ss_family == AF_INET6) { edns_size = nsd->ipv6_edns_size; } else #endif edns_size = nsd->ipv4_edns_size; if (q->edns.maxlen < edns_size) { q->maxlen = q->edns.maxlen; } else { q->maxlen = edns_size; } #if defined(INET6) && !defined(IPV6_USE_MIN_MTU) && !defined(IPV6_MTU) /* * Use IPv6 minimum MTU to avoid sending * packets that are too large for some links. * IPv6 will not automatically fragment in * this case (unlike IPv4). */ if (q->addr.ss_family == AF_INET6 && q->maxlen > IPV6_MIN_MTU) { q->maxlen = IPV6_MIN_MTU; } #endif } /* Strip the OPT resource record off... */ buffer_set_position(q->packet, q->edns.position); buffer_set_limit(q->packet, q->edns.position); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1); } return NSD_RC_OK; } /* * Processes TSIG. * Sets error when tsig does not verify on the query. */ static nsd_rc_type process_tsig(struct query* q) { if(q->tsig.status == TSIG_ERROR) return NSD_RC_FORMAT; if(q->tsig.status == TSIG_OK) { if(!tsig_from_query(&q->tsig)) { char a[128]; addr2str(&q->addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig (%s) for key %s from %s", tsig_error(q->tsig.error_code), dname_to_string(q->tsig.key_name, NULL), a); return NSD_RC_NOTAUTH; } buffer_set_limit(q->packet, q->tsig.position); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) - 1); tsig_prepare(&q->tsig); tsig_update(&q->tsig, q->packet, buffer_limit(q->packet)); if(!tsig_verify(&q->tsig)) { char a[128]; addr2str(&q->addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig signature for key %s from %s", dname_to_string(q->tsig.key->name, NULL), a); return NSD_RC_NOTAUTH; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "query good tsig signature for %s", dname_to_string(q->tsig.key->name, NULL))); } return NSD_RC_OK; } /* * Check notify acl and forward to xfrd (or return an error). */ static query_state_type answer_notify(struct nsd* nsd, struct query *query) { int acl_num, acl_num_xfr; struct acl_options *why; nsd_rc_type rc; struct zone_options* zone_opt; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s processing acl", dname_to_string(query->qname, NULL))); zone_opt = zone_options_find(nsd->options, query->qname); if(!zone_opt) return query_error(query, NSD_RC_NXDOMAIN); if(!nsd->this_child) /* we are in debug mode or something */ return query_error(query, NSD_RC_SERVFAIL); if(!tsig_find_rr(&query->tsig, query->packet)) { DEBUG(DEBUG_XFRD,2, (LOG_ERR, "bad tsig RR format")); return query_error(query, NSD_RC_FORMAT); } rc = process_tsig(query); if(rc != NSD_RC_OK) return query_error(query, rc); /* check if it passes acl */ if((acl_num = acl_check_incoming(zone_opt->pattern->allow_notify, query, &why)) != -1) { sig_atomic_t mode = NSD_PASS_TO_XFRD; int s = nsd->this_child->parent_fd; uint16_t sz; uint32_t acl_send = htonl(acl_num); uint32_t acl_xfr; size_t pos; /* Find priority candidate for request XFR. -1 if no match */ acl_num_xfr = acl_check_incoming( zone_opt->pattern->request_xfr, query, NULL); acl_xfr = htonl(acl_num_xfr); assert(why); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "got notify %s passed acl %s %s", dname_to_string(query->qname, NULL), why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); sz = buffer_limit(query->packet); if(buffer_limit(query->packet) > MAX_PACKET_SIZE) return query_error(query, NSD_RC_SERVFAIL); /* forward to xfrd for processing Note. Blocking IPC I/O, but acl is OK. */ sz = htons(sz); if(!write_socket(s, &mode, sizeof(mode)) || !write_socket(s, &sz, sizeof(sz)) || !write_socket(s, buffer_begin(query->packet), buffer_limit(query->packet)) || !write_socket(s, &acl_send, sizeof(acl_send)) || !write_socket(s, &acl_xfr, sizeof(acl_xfr))) { log_msg(LOG_ERR, "error in IPC notify server2main, %s", strerror(errno)); return query_error(query, NSD_RC_SERVFAIL); } if(verbosity >= 1) { uint32_t serial = 0; char address[128]; addr2str(&query->addr, address, sizeof(address)); if(packet_find_notify_serial(query->packet, &serial)) VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u", dname_to_string(query->qname, NULL), address, (unsigned)serial)); else VERBOSITY(1, (LOG_INFO, "notify for %s from %s", dname_to_string(query->qname, NULL), address)); } /* create notify reply - keep same query contents */ QR_SET(query->packet); /* This is an answer. */ AA_SET(query->packet); /* we are authoritative. */ ANCOUNT_SET(query->packet, 0); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); RCODE_SET(query->packet, RCODE_OK); /* Error code. */ /* position is right after the query */ pos = buffer_position(query->packet); buffer_clear(query->packet); buffer_set_position(query->packet, pos); /* tsig is added in add_additional later (if needed) */ return QUERY_PROCESSED; } if (verbosity >= 2) { char address[128]; addr2str(&query->addr, address, sizeof(address)); VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s%s", dname_to_string(query->qname, NULL), address, why?why->key_name:"no acl matches", why?why->ip_address_spec:".")); } return query_error(query, NSD_RC_REFUSE); } /* * Answer a query in the CHAOS class. */ static query_state_type answer_chaos(struct nsd *nsd, query_type *q) { AA_CLR(q->packet); switch (q->qtype) { case TYPE_ANY: case TYPE_TXT: if ((q->qname->name_size == 11 && memcmp(dname_name(q->qname), "\002id\006server", 11) == 0) || (q->qname->name_size == 15 && memcmp(dname_name(q->qname), "\010hostname\004bind", 15) == 0)) { /* Add ID */ query_addtxt(q, buffer_begin(q->packet) + QHEADERSZ, CLASS_CH, 0, nsd->identity); ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1); } else if ((q->qname->name_size == 16 && memcmp(dname_name(q->qname), "\007version\006server", 16) == 0) || (q->qname->name_size == 14 && memcmp(dname_name(q->qname), "\007version\004bind", 14) == 0)) { if(!nsd->options->hide_version) { /* Add version */ query_addtxt(q, buffer_begin(q->packet) + QHEADERSZ, CLASS_CH, 0, nsd->version); ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1); } else { RCODE_SET(q->packet, RCODE_REFUSE); } } else { RCODE_SET(q->packet, RCODE_REFUSE); } break; default: RCODE_SET(q->packet, RCODE_REFUSE); break; } return QUERY_PROCESSED; } /* * Find the covering NSEC for a non-existent domain name. Normally * the NSEC will be located at CLOSEST_MATCH, except when it is an * empty non-terminal. In this case the NSEC may be located at the * previous domain name (in canonical ordering). */ static domain_type * find_covering_nsec(domain_type *closest_match, zone_type *zone, rrset_type **nsec_rrset) { assert(closest_match); assert(nsec_rrset); /* loop away temporary created domains. For real ones it is &RBTREE_NULL */ #ifdef USE_RADIX_TREE while (closest_match->rnode == NULL) #else while (closest_match->node.parent == NULL) #endif closest_match = closest_match->parent; while (closest_match) { *nsec_rrset = domain_find_rrset(closest_match, zone, TYPE_NSEC); if (*nsec_rrset) { return closest_match; } if (closest_match == zone->apex) { /* Don't look outside the current zone. */ return NULL; } closest_match = domain_previous(closest_match); } return NULL; } struct additional_rr_types { uint16_t rr_type; rr_section_type rr_section; }; struct additional_rr_types default_additional_rr_types[] = { { TYPE_A, ADDITIONAL_A_SECTION }, { TYPE_AAAA, ADDITIONAL_AAAA_SECTION }, { 0, (rr_section_type) 0 } }; struct additional_rr_types swap_aaaa_additional_rr_types[] = { { TYPE_AAAA, ADDITIONAL_A_SECTION }, { TYPE_A, ADDITIONAL_AAAA_SECTION }, { 0, (rr_section_type) 0 } }; struct additional_rr_types rt_additional_rr_types[] = { { TYPE_A, ADDITIONAL_A_SECTION }, { TYPE_AAAA, ADDITIONAL_AAAA_SECTION }, { TYPE_X25, ADDITIONAL_OTHER_SECTION }, { TYPE_ISDN, ADDITIONAL_OTHER_SECTION }, { 0, (rr_section_type) 0 } }; static void add_additional_rrsets(struct query *query, answer_type *answer, rrset_type *master_rrset, size_t rdata_index, int allow_glue, struct additional_rr_types types[]) { size_t i; assert(query); assert(answer); assert(master_rrset); assert(rdata_atom_is_domain(rrset_rrtype(master_rrset), rdata_index)); for (i = 0; i < master_rrset->rr_count; ++i) { int j; domain_type *additional = rdata_atom_domain(master_rrset->rrs[i].rdatas[rdata_index]); domain_type *match = additional; assert(additional); if (!allow_glue && domain_is_glue(match, query->zone)) continue; /* * Check to see if we need to generate the dependent * based on a wildcard domain. */ while (!match->is_existing) { match = match->parent; } if (additional != match && domain_wildcard_child(match)) { domain_type *wildcard_child = domain_wildcard_child(match); domain_type *temp = (domain_type *) region_alloc( query->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE temp->rnode = NULL; temp->dname = additional->dname; #else memcpy(&temp->node, &additional->node, sizeof(rbnode_type)); temp->node.parent = NULL; #endif temp->number = additional->number; temp->parent = match; temp->wildcard_child_closest_match = temp; temp->rrsets = wildcard_child->rrsets; temp->is_existing = wildcard_child->is_existing; additional = temp; } for (j = 0; types[j].rr_type != 0; ++j) { rrset_type *rrset = domain_find_rrset( additional, query->zone, types[j].rr_type); if (rrset) { answer_add_rrset(answer, types[j].rr_section, additional, rrset); } } } } static int answer_needs_ns(struct query* query) { assert(query); /* Currently, only troublesome for DNSKEY and DS, * cuz their RRSETs are quite large. */ return (query->qtype != TYPE_DNSKEY && query->qtype != TYPE_DS); } static int add_rrset(struct query *query, answer_type *answer, rr_section_type section, domain_type *owner, rrset_type *rrset) { int result; assert(query); assert(answer); assert(owner); assert(rrset); assert(rrset_rrclass(rrset) == CLASS_IN); result = answer_add_rrset(answer, section, owner, rrset); if(minimal_responses && section != AUTHORITY_SECTION && query->qtype != TYPE_NS) return result; switch (rrset_rrtype(rrset)) { case TYPE_NS: #if defined(INET6) /* if query over IPv6, swap A and AAAA; put AAAA first */ add_additional_rrsets(query, answer, rrset, 0, 1, (query->addr.ss_family == AF_INET6)? swap_aaaa_additional_rr_types: default_additional_rr_types); #else add_additional_rrsets(query, answer, rrset, 0, 1, default_additional_rr_types); #endif break; case TYPE_MB: add_additional_rrsets(query, answer, rrset, 0, 0, default_additional_rr_types); break; case TYPE_MX: case TYPE_KX: add_additional_rrsets(query, answer, rrset, 1, 0, default_additional_rr_types); break; case TYPE_RT: add_additional_rrsets(query, answer, rrset, 1, 0, rt_additional_rr_types); break; case TYPE_SRV: add_additional_rrsets(query, answer, rrset, 3, 0, default_additional_rr_types); break; default: break; } return result; } /* returns 0 on error, or the domain number for to_name. from_name is changes to to_name by the DNAME rr. DNAME rr is from src to dest. closest encloser encloses the to_name. */ static size_t query_synthesize_cname(struct query* q, struct answer* answer, const dname_type* from_name, const dname_type* to_name, domain_type* src, domain_type* to_closest_encloser, domain_type** to_closest_match, uint32_t ttl) { /* add temporary domains for from_name and to_name and all their (not allocated yet) parents */ /* any domains below src are not_existing (because of DNAME at src) */ int i; domain_type* cname_domain; domain_type* cname_dest; rrset_type* rrset; /* allocate source part */ domain_type* lastparent = src; assert(q && answer && from_name && to_name && src && to_closest_encloser); assert(to_closest_match); for(i=0; i < from_name->label_count - domain_dname(src)->label_count; i++) { domain_type* newdom = query_get_tempdomain(q); if(!newdom) return 0; newdom->is_existing = 1; newdom->parent = lastparent; #ifdef USE_RADIX_TREE newdom->dname #else newdom->node.key #endif = dname_partial_copy(q->region, from_name, domain_dname(src)->label_count + i + 1); if(dname_compare(domain_dname(newdom), q->qname) == 0) { /* 0 good for query name, otherwise new number */ newdom->number = 0; } DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain src %d. %s nr %d", i, domain_to_string(newdom), (int)newdom->number)); lastparent = newdom; } cname_domain = lastparent; /* allocate dest part */ lastparent = to_closest_encloser; for(i=0; i < to_name->label_count - domain_dname(to_closest_encloser)->label_count; i++) { domain_type* newdom = query_get_tempdomain(q); if(!newdom) return 0; newdom->is_existing = 0; newdom->parent = lastparent; #ifdef USE_RADIX_TREE newdom->dname #else newdom->node.key #endif = dname_partial_copy(q->region, to_name, domain_dname(to_closest_encloser)->label_count + i + 1); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain dest %d. %s nr %d", i, domain_to_string(newdom), (int)newdom->number)); lastparent = newdom; } cname_dest = lastparent; *to_closest_match = cname_dest; /* allocate the CNAME RR */ rrset = (rrset_type*) region_alloc(q->region, sizeof(rrset_type)); memset(rrset, 0, sizeof(rrset_type)); rrset->zone = q->zone; rrset->rr_count = 1; rrset->rrs = (rr_type*) region_alloc(q->region, sizeof(rr_type)); memset(rrset->rrs, 0, sizeof(rr_type)); rrset->rrs->owner = cname_domain; rrset->rrs->ttl = ttl; rrset->rrs->type = TYPE_CNAME; rrset->rrs->klass = CLASS_IN; rrset->rrs->rdata_count = 1; rrset->rrs->rdatas = (rdata_atom_type*)region_alloc(q->region, sizeof(rdata_atom_type)); rrset->rrs->rdatas->domain = cname_dest; if(!add_rrset(q, answer, ANSWER_SECTION, cname_domain, rrset)) { log_msg(LOG_ERR, "could not add synthesized CNAME rrset to packet"); } return cname_dest->number; } /* * Answer delegation information. * * DNSSEC: Include the DS RRset if present. Otherwise include an NSEC * record proving the DS RRset does not exist. */ static void answer_delegation(query_type *query, answer_type *answer) { assert(answer); assert(query->delegation_domain); assert(query->delegation_rrset); if (query->cname_count == 0) { AA_CLR(query->packet); } else { AA_SET(query->packet); } add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, query->delegation_rrset); if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { rrset_type *rrset; if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_DS))) { add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, rrset); #ifdef NSEC3 } else if (query->zone->nsec3_param) { nsec3_answer_delegation(query, answer); #endif } else if ((rrset = domain_find_rrset(query->delegation_domain, query->zone, TYPE_NSEC))) { add_rrset(query, answer, AUTHORITY_SECTION, query->delegation_domain, rrset); } } } /* * Answer SOA information. */ static void answer_soa(struct query *query, answer_type *answer) { if (query->qclass != CLASS_ANY) { add_rrset(query, answer, AUTHORITY_SECTION, query->zone->apex, query->zone->soa_nx_rrset); } } /* * Answer that the domain name exists but there is no RRset with the * requested type. * * DNSSEC: Include the correct NSEC record proving that the type does * not exist. In the wildcard no data (3.1.3.4) case the wildcard IS * NOT expanded, so the ORIGINAL parameter must point to the original * wildcard entry, not to the generated entry. */ static void answer_nodata(struct query *query, answer_type *answer, domain_type *original) { if (query->cname_count == 0) { answer_soa(query, answer); } #ifdef NSEC3 if (query->edns.dnssec_ok && query->zone->nsec3_param) { nsec3_answer_nodata(query, answer, original); } else #endif if (query->edns.dnssec_ok && zone_is_secure(query->zone)) { domain_type *nsec_domain; rrset_type *nsec_rrset; nsec_domain = find_covering_nsec(original, query->zone, &nsec_rrset); if (nsec_domain) { add_rrset(query, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } } static void answer_nxdomain(query_type *query, answer_type *answer) { RCODE_SET(query->packet, RCODE_NXDOMAIN); answer_soa(query, answer); } /* * Answer domain information (or SOA if we do not have an RRset for * the type specified by the query). */ static void answer_domain(struct nsd* nsd, struct query *q, answer_type *answer, domain_type *domain, domain_type *original) { rrset_type *rrset; if (q->qtype == TYPE_ANY) { int added = 0; for (rrset = domain_find_any_rrset(domain, q->zone); rrset; rrset = rrset->next) { if (rrset->zone == q->zone #ifdef NSEC3 && rrset_rrtype(rrset) != TYPE_NSEC3 #endif /* * Don't include the RRSIG RRset when * DNSSEC is used, because it is added * automatically on an per-RRset basis. */ && !(q->edns.dnssec_ok && zone_is_secure(q->zone) && rrset_rrtype(rrset) == TYPE_RRSIG)) { add_rrset(q, answer, ANSWER_SECTION, domain, rrset); ++added; } } if (added == 0) { answer_nodata(q, answer, original); return; } #ifdef NSEC3 } else if (q->qtype == TYPE_NSEC3) { answer_nodata(q, answer, original); return; #endif } else if ((rrset = domain_find_rrset(domain, q->zone, q->qtype))) { add_rrset(q, answer, ANSWER_SECTION, domain, rrset); } else if ((rrset = domain_find_rrset(domain, q->zone, TYPE_CNAME))) { int added; /* * If the CNAME is not added it is already in the * answer, so we have a CNAME loop. Don't follow the * CNAME target in this case. */ added = add_rrset(q, answer, ANSWER_SECTION, domain, rrset); assert(rrset->rr_count > 0); if (added) { /* only process first CNAME record */ domain_type *closest_match = rdata_atom_domain(rrset->rrs[0].rdatas[0]); domain_type *closest_encloser = closest_match; zone_type* origzone = q->zone; ++q->cname_count; answer_lookup_zone(nsd, q, answer, closest_match->number, closest_match == closest_encloser, closest_match, closest_encloser, domain_dname(closest_match)); q->zone = origzone; } return; } else { answer_nodata(q, answer, original); return; } if (q->qclass != CLASS_ANY && q->zone->ns_rrset && answer_needs_ns(q) && !minimal_responses) { add_rrset(q, answer, OPTIONAL_AUTHORITY_SECTION, q->zone->apex, q->zone->ns_rrset); } } /* * Answer with authoritative data. If a wildcard is matched the owner * name will be expanded to the domain name specified by * DOMAIN_NUMBER. DOMAIN_NUMBER 0 (zero) is reserved for the original * query name. * * DNSSEC: Include the necessary NSEC records in case the request * domain name does not exist and/or a wildcard match does not exist. */ static void answer_authoritative(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname) { domain_type *match; domain_type *original = closest_match; domain_type *dname_ce; rrset_type *rrset; #ifdef NSEC3 if(exact && domain_has_only_NSEC3(closest_match, q->zone)) { exact = 0; /* pretend it does not exist */ if(closest_encloser->parent) closest_encloser = closest_encloser->parent; } #endif /* NSEC3 */ if((dname_ce = find_dname_above(closest_encloser, q->zone)) != NULL) { /* occlude the found data, the DNAME is closest_encloser */ closest_encloser = dname_ce; exact = 0; } if (exact) { match = closest_match; } else if ((rrset=domain_find_rrset(closest_encloser, q->zone, TYPE_DNAME))) { /* process DNAME */ const dname_type* name = qname; domain_type *dest = rdata_atom_domain(rrset->rrs[0].rdatas[0]); int added; assert(rrset->rr_count > 0); if(domain_number != 0) /* we followed CNAMEs or DNAMEs */ name = domain_dname(closest_match); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "expanding DNAME for q=%s", dname_to_string(name, NULL))); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->src is %s", domain_to_string(closest_encloser))); DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->dest is %s", domain_to_string(dest))); /* if the DNAME set is not added we have a loop, do not follow */ added = add_rrset(q, answer, ANSWER_SECTION, closest_encloser, rrset); if(added) { domain_type* src = closest_encloser; const dname_type* newname = dname_replace(q->region, name, domain_dname(src), domain_dname(dest)); size_t newnum = 0; zone_type* origzone = q->zone; ++q->cname_count; if(!newname) { /* newname too long */ RCODE_SET(q->packet, RCODE_YXDOMAIN); return; } DEBUG(DEBUG_QUERY,2, (LOG_INFO, "->result is %s", dname_to_string(newname, NULL))); /* follow the DNAME */ (void)namedb_lookup(nsd->db, newname, &closest_match, &closest_encloser); /* synthesize CNAME record */ newnum = query_synthesize_cname(q, answer, name, newname, src, closest_encloser, &closest_match, rrset->rrs[0].ttl); if(!newnum) { /* could not synthesize the CNAME. */ /* return previous CNAMEs to make resolver recurse for us */ return; } answer_lookup_zone(nsd, q, answer, newnum, closest_match == closest_encloser, closest_match, closest_encloser, newname); q->zone = origzone; } if(!added) /* log the error so operator can find looping recursors */ log_msg(LOG_INFO, "DNAME processing stopped due to loop, qname %s", dname_to_string(q->qname, NULL)); return; } else if (domain_wildcard_child(closest_encloser)) { /* Generate the domain from the wildcard. */ domain_type *wildcard_child = domain_wildcard_child(closest_encloser); #ifdef RATELIMIT q->wildcard_domain = wildcard_child; #endif match = (domain_type *) region_alloc(q->region, sizeof(domain_type)); #ifdef USE_RADIX_TREE match->rnode = NULL; match->dname = wildcard_child->dname; #else memcpy(&match->node, &wildcard_child->node, sizeof(rbnode_type)); match->node.parent = NULL; #endif match->parent = closest_encloser; match->wildcard_child_closest_match = match; match->number = domain_number; match->rrsets = wildcard_child->rrsets; match->is_existing = wildcard_child->is_existing; #ifdef NSEC3 match->nsec3 = wildcard_child->nsec3; /* copy over these entries: match->nsec3_is_exact = wildcard_child->nsec3_is_exact; match->nsec3_cover = wildcard_child->nsec3_cover; match->nsec3_wcard_child_cover = wildcard_child->nsec3_wcard_child_cover; match->nsec3_ds_parent_is_exact = wildcard_child->nsec3_ds_parent_is_exact; match->nsec3_ds_parent_cover = wildcard_child->nsec3_ds_parent_cover; */ if (q->edns.dnssec_ok && q->zone->nsec3_param) { /* Only add nsec3 wildcard data when do bit is set */ nsec3_answer_wildcard(q, answer, wildcard_child, qname); } #endif /* * Remember the original domain in case a Wildcard No * Data (3.1.3.4) response needs to be generated. In * this particular case the wildcard IS NOT * expanded. */ original = wildcard_child; } else { match = NULL; } /* Authoritative zone. */ #ifdef NSEC3 if (q->edns.dnssec_ok && q->zone->nsec3_param) { nsec3_answer_authoritative(&match, q, answer, closest_encloser, qname); } else #endif if (q->edns.dnssec_ok && zone_is_secure(q->zone)) { if (match != closest_encloser) { domain_type *nsec_domain; rrset_type *nsec_rrset; /* * No match found or generated from wildcard, * include NSEC record. */ nsec_domain = find_covering_nsec(closest_match, q->zone, &nsec_rrset); if (nsec_domain) { add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } if (!match) { domain_type *nsec_domain; rrset_type *nsec_rrset; /* * No match and no wildcard. Include NSEC * proving there is no wildcard. */ nsec_domain = find_covering_nsec(closest_encloser->wildcard_child_closest_match, q->zone, &nsec_rrset); if (nsec_domain) { add_rrset(q, answer, AUTHORITY_SECTION, nsec_domain, nsec_rrset); } } } #ifdef NSEC3 if (RCODE(q->packet)!=RCODE_OK) { return; /* nsec3 collision failure */ } #endif if (match) { answer_domain(nsd, q, answer, match, original); } else { answer_nxdomain(q, answer); } } /* * qname may be different after CNAMEs have been followed from query->qname. */ static void answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, size_t domain_number, int exact, domain_type *closest_match, domain_type *closest_encloser, const dname_type *qname) { q->zone = domain_find_zone(nsd->db, closest_encloser); if (!q->zone) { /* no zone for this */ if(q->cname_count == 0) RCODE_SET(q->packet, RCODE_REFUSE); return; } assert(closest_encloser); /* otherwise, no q->zone would be found */ 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; } /* now move up the closest encloser until it exists, previous * (possibly empty) closest encloser was useful to finding the zone * (for empty zones too), but now we want actual data nodes */ if (closest_encloser && !closest_encloser->is_existing) { exact = 0; while (closest_encloser != NULL && !closest_encloser->is_existing) closest_encloser = closest_encloser->parent; } /* * See RFC 4035 (DNSSEC protocol) section 3.1.4.1 Responding * to Queries for DS RRs. */ if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) { /* * Type DS query at a zone cut, use the responsible * parent zone to generate the answer if we are * authoritative for the parent zone. */ zone_type *zone = domain_find_parent_zone(nsd->db, q->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) */ if(q->zone && q->zone->opts && q->zone->opts->pattern && q->zone->opts->pattern->request_xfr != 0 && !q->zone->is_ok) { if(q->cname_count == 0) RCODE_SET(q->packet, RCODE_SERVFAIL); return; } if (exact && q->qtype == TYPE_DS && closest_encloser == q->zone->apex) { /* * Type DS query at the zone apex (and the server is * not authoritative for the parent zone). */ if (q->qclass == CLASS_ANY) { AA_CLR(q->packet); } else { AA_SET(q->packet); } answer_nodata(q, answer, closest_encloser); } else { q->delegation_domain = domain_find_ns_rrsets( closest_encloser, q->zone, &q->delegation_rrset); if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) { q->delegation_domain = NULL; /* use higher DNAME */ } if (!q->delegation_domain || (exact && q->qtype == TYPE_DS && closest_encloser == q->delegation_domain)) { if (q->qclass == CLASS_ANY) { AA_CLR(q->packet); } else { AA_SET(q->packet); } answer_authoritative(nsd, q, answer, domain_number, exact, closest_match, closest_encloser, qname); } else { answer_delegation(q, answer); } } } static void answer_query(struct nsd *nsd, struct query *q) { domain_type *closest_match; domain_type *closest_encloser; int exact; uint16_t offset; answer_type answer; answer_init(&answer); exact = namedb_lookup(nsd->db, q->qname, &closest_match, &closest_encloser); answer_lookup_zone(nsd, q, &answer, 0, exact, closest_match, closest_encloser, q->qname); ZTATUP2(nsd, q->zone, opcode, q->opcode); ZTATUP2(nsd, q->zone, qtype, q->qtype); ZTATUP2(nsd, q->zone, qclass, q->qclass); offset = dname_label_offsets(q->qname)[domain_dname(closest_encloser)->label_count - 1] + QHEADERSZ; query_add_compression_domain(q, closest_encloser, offset); encode_answer(q, &answer); query_clear_compression_tables(q); } void query_prepare_response(query_type *q) { uint16_t flags; /* * Preserve the data up-to the current packet's limit. */ buffer_set_position(q->packet, buffer_limit(q->packet)); buffer_set_limit(q->packet, buffer_capacity(q->packet)); /* * Reserve space for the EDNS records if required. */ q->reserved_space = edns_reserved_space(&q->edns); q->reserved_space += tsig_reserved_space(&q->tsig); /* Update the flags. */ flags = FLAGS(q->packet); flags &= 0x0100U; /* Preserve the RD flag. */ /* CD flag must be cleared for auth answers */ flags |= 0x8000U; /* Set the QR flag. */ FLAGS_SET(q->packet, flags); } /* * Processes the query. * */ query_state_type query_process(query_type *q, nsd_type *nsd) { /* The query... */ nsd_rc_type rc; query_state_type query_state; uint16_t arcount; /* Sanity checks */ if (buffer_limit(q->packet) < QHEADERSZ) { /* packet too small to contain DNS header. Now packet investigation macros will work without problems. */ return QUERY_DISCARDED; } if (QR(q->packet)) { /* Not a query? Drop it on the floor. */ return QUERY_DISCARDED; } /* check opcode early on, because new opcodes may have different * specification of the meaning of the rest of the packet */ q->opcode = OPCODE(q->packet); if(q->opcode != OPCODE_QUERY && q->opcode != OPCODE_NOTIFY) { if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; return query_error(q, NSD_RC_IMPL); } if (RCODE(q->packet) != RCODE_OK || !process_query_section(q)) { return query_formerr(q, nsd); } /* Update statistics. */ STATUP2(nsd, opcode, q->opcode); STATUP2(nsd, qtype, q->qtype); STATUP2(nsd, qclass, q->qclass); if (q->opcode != OPCODE_QUERY) { if (q->opcode == OPCODE_NOTIFY) { return answer_notify(nsd, q); } else { if(query_ratelimit_err(nsd)) return QUERY_DISCARDED; return query_error(q, NSD_RC_IMPL); } } /* Dont bother to answer more than one question at once... */ if (QDCOUNT(q->packet) != 1) { FLAGS_SET(q->packet, 0); return query_formerr(q, nsd); } /* Ignore settings of flags */ /* Dont allow any records in the answer or authority section... except for IXFR queries. */ if (ANCOUNT(q->packet) != 0 || (q->qtype!=TYPE_IXFR && NSCOUNT(q->packet) != 0)) { return query_formerr(q, nsd); } if(q->qtype==TYPE_IXFR && NSCOUNT(q->packet) > 0) { int i; /* skip ixfr soa information data here */ for(i=0; i< NSCOUNT(q->packet); i++) if(!packet_skip_rr(q->packet, 0)) return query_formerr(q, nsd); } arcount = ARCOUNT(q->packet); if (arcount > 0) { /* According to draft-ietf-dnsext-rfc2671bis-edns0-10: * "The placement flexibility for the OPT RR does not * override the need for the TSIG or SIG(0) RRs to be * the last in the additional section whenever they are * present." * So we should not have to check for TSIG RR before * OPT RR. Keep the code for backwards compatibility. */ /* see if tsig is before edns record */ if (!tsig_parse_rr(&q->tsig, q->packet)) return query_formerr(q, nsd); if(q->tsig.status != TSIG_NOT_PRESENT) --arcount; } /* See if there is an OPT RR. */ if (arcount > 0) { if (edns_parse_record(&q->edns, q->packet, q, nsd)) --arcount; } /* See if there is a TSIG RR. */ if (arcount > 0 && q->tsig.status == TSIG_NOT_PRESENT) { /* see if tsig is after the edns record */ if (!tsig_parse_rr(&q->tsig, q->packet)) return query_formerr(q, nsd); if(q->tsig.status != TSIG_NOT_PRESENT) --arcount; } /* If more RRs left in Add. Section, FORMERR. */ if (arcount > 0) { return query_formerr(q, nsd); } /* Do we have any trailing garbage? */ #ifdef STRICT_MESSAGE_PARSE if (buffer_remaining(q->packet) > 0) { /* If we're strict.... */ return query_formerr(q, nsd); } #endif /* Remove trailing garbage. */ buffer_set_limit(q->packet, buffer_position(q->packet)); rc = process_tsig(q); if (rc != NSD_RC_OK) { return query_error(q, rc); } rc = process_edns(nsd, q); if (rc != NSD_RC_OK) { /* We should not return FORMERR, but BADVERS (=16). * BADVERS is created with Ext. RCODE, followed by RCODE. * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16). * Thus RCODE = NOERROR = NSD_RC_OK. */ return query_error(q, NSD_RC_OK); } query_prepare_response(q); if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) { if (q->qclass == CLASS_CH) { return answer_chaos(nsd, q); } else { return query_error(q, NSD_RC_REFUSE); } } query_state = answer_axfr_ixfr(nsd, q); if (query_state == QUERY_PROCESSED || query_state == QUERY_IN_AXFR) { return query_state; } if(q->qtype == TYPE_ANY && nsd->options->refuse_any && !q->tcp) { TC_SET(q->packet); return query_error(q, NSD_RC_OK); } answer_query(nsd, q); return QUERY_PROCESSED; } void query_add_optional(query_type *q, nsd_type *nsd) { struct edns_data *edns = &nsd->edns_ipv4; #if defined(INET6) if (q->addr.ss_family == AF_INET6) { edns = &nsd->edns_ipv6; } #endif if (RCODE(q->packet) == RCODE_FORMAT) { return; } switch (q->edns.status) { case EDNS_NOT_PRESENT: break; case EDNS_OK: if (q->edns.dnssec_ok) edns->ok[7] = 0x80; else edns->ok[7] = 0x00; buffer_write(q->packet, edns->ok, OPT_LEN); if(q->edns.opt_reserved_space == 0 || !buffer_available( q->packet, 2+q->edns.opt_reserved_space)) { /* fill with NULLs */ buffer_write(q->packet, edns->rdata_none, OPT_RDATA); } else { /* rdata length */ buffer_write_u16(q->packet, q->edns.opt_reserved_space); /* edns options */ if(q->edns.nsid) { /* nsid opt header */ buffer_write(q->packet, edns->nsid, OPT_HDR); /* nsid payload */ buffer_write(q->packet, nsd->nsid, nsd->nsid_len); } } ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); STATUP(nsd, edns); ZTATUP(nsd, q->zone, edns); break; case EDNS_ERROR: if (q->edns.dnssec_ok) edns->error[7] = 0x80; else edns->error[7] = 0x00; buffer_write(q->packet, edns->error, OPT_LEN); buffer_write(q->packet, edns->rdata_none, OPT_RDATA); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); STATUP(nsd, ednserr); ZTATUP(nsd, q->zone, ednserr); break; } if (q->tsig.status != TSIG_NOT_PRESENT) { if (q->tsig.status == TSIG_ERROR || q->tsig.error_code != TSIG_ERROR_NOERROR) { tsig_error_reply(&q->tsig); tsig_append_rr(&q->tsig, q->packet); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); } else if(q->tsig.status == TSIG_OK && q->tsig.error_code == TSIG_ERROR_NOERROR) { if(q->tsig_prepare_it) tsig_prepare(&q->tsig); if(q->tsig_update_it) tsig_update(&q->tsig, q->packet, buffer_position(q->packet)); if(q->tsig_sign_it) { tsig_sign(&q->tsig); tsig_append_rr(&q->tsig, q->packet); ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1); } } } } nsd-4.1.26/nsd-control.8.in0000664000175000017500000002255613401455025014777 0ustar wouterwouter.TH "nsd\-control" "8" "Dec 4, 2018" "NLnet Labs" "nsd 4.1.26" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-control, .B nsd\-control\-setup \- NSD remote server control utility. .SH "SYNOPSIS" .B nsd\-control .RB [ \-c .IR cfgfile ] .RB [ \-s .IR server ] .IR command .SH "DESCRIPTION" .B nsd\-control performs remote administration on the \fInsd\fR(8) DNS server. It reads the configuration file, contacts the nsd server over SSL, sends the command and displays the result. .P The available options are: .TP .B \-h Show the version and commandline option help. .TP .B \-c \fIcfgfile The config file to read with settings. If not given the default config file @nsdconfigfile@ is used. .TP .B \-s \fIserver[@port] IPv4 or IPv6 address of the server to contact. If not given, the address is read from the config file. .SH "COMMANDS" There are several commands that the server understands. .TP .B start Start the server. Simply execs \fInsd\fR(8). The nsd executable is searched for in the \fBPATH\fR set in the environment. It is started with the config file specified using \fI\-c\fR or the default config file. .TP .B stop Stop the server. The server daemon exits. .TP .B reload [] Reload zonefiles and reopen logfile. Without argument reads changed zonefiles. With argument reads the zonefile for the given zone and loads it. .TP .B reconfig Reload nsd.conf and apply changes to TSIG keys and configuration patterns, and apply the changes to add and remove zones that are mentioned in the config. Other changes are not applied, such as listening ip address and port and chroot, also per-zone statistics are not applied. The pattern updates means that the configuration options for zones (request\-xfr, zonefile, notify, ...) are updated. Also new patterns are available for use with the addzone command. .TP .B repattern Same as the reconfig option. .TP .B log_reopen Reopen the logfile, for log rotate that wants to move the logfile away and create a new logfile. The log can also be reopened with kill \-HUP (which also reloads all zonefiles). .TP .B status Display server status. Exit code 3 if not running (the connection to the port is refused), 1 on error, 0 if running. .TP .B stats Output a sequence of name=value lines with statistics information, requires NSD to be compiled with this option enabled. .TP .B stats_noreset Same as stats, but does not zero the counters. .TP .B addzone Add a new zone to the running server. The zone is added to the zonelist file on disk, so it stays after a restart. The pattern name determines the options for the new zone. For slave zones a zone transfer is immediately attempted. For zones with a zonefile, the zone file is attempted to be read in. .TP .B delzone Remove the zone from the running server. The zone is removed from the zonelist file on disk, from the nsd.db file and from the memory. If it had a zonefile, this remains (but may be outdated). Zones configured inside nsd.conf itself cannot be removed this way because the daemon does not write to the nsd.conf file, you need to add such zones to the zonelist file to be able to delete them with the delzone command. .TP .B changezone Change a zone to use the pattern for options. The zone is deleted and added in one operation, changing it to use the new pattern for the zone options. Zones configured in nsd.conf cannot be changed like this, instead edit the nsd.conf (or the included file in nsd.conf) and reconfig. .TP .B addzones Add zones read from stdin of nsd\-control. Input is read per line, with name space patternname on a line. For bulk additions. .TP .B delzones Remove zones read from stdin of nsd\-control. Input is one name per line. For bulk removals. .TP .B write [] Write zonefiles to disk, or the given zonefile to disk. Zones that have changed (via AXFR or IXFR) are written, or if the zonefile has not been created yet then it is created. Directory components of the zonefile path are created if necessary. .TP .B notify [] Send NOTIFY messages to slave servers. Sends to the IP addresses configured in the 'notify:' lists for the master zones hosted on this server. Usually NSD sends NOTIFY messages right away when a master zone serial is updated. If a zone is given, notifies are sent for that zone. These slave servers are supposed to initiate a zone transfer request later (to this server or another master), this can be allowed via the 'provide\-xfr:' acl list configuration. .TP .B transfer [] Attempt to update slave zones that are hosted on this server by contacting the masters. The masters are configured via 'request\-xfr:' lists. If a zone is given, that zone is updated. Usually NSD receives a NOTIFY from the masters (configured via 'allow\-notify:' acl list) that a new zone serial has to be transferred. For zones with no content, NSD may have backed off from asking often because the masters did not respond, but this command will reset the backoff to its initial timeout, for frequent retries. .TP .B force_transfer [] Force update slave zones that are hosted on this server. Even if the master hosts the same serial number of the zone, a full AXFR is performed to fetch it. If you want to use IXFR and check that the serial number increases, use the 'transfer' command. .TP .B zonestatus [] Print state of the zone, the serial numbers and since when they have been acquired. Also prints the notify action (to which server), and zone transfer (and from which master) if there is activity right now. The state of the zone is printed as: 'master' (master zones), 'ok' (slave zone is up\-to\-date), 'expired' (slave zone has expired), 'refreshing' (slave zone has transfers active). The serial numbers printed are the 'served\-serial' (currently active), the 'commit\-serial' (is in reload), the 'notified\-serial' (got notify, busy fetching the data). The serial numbers are only printed if such a serial number is available. .TP .B serverpid Prints the PID of the server process. This is used for statistics (and only works when NSD is compiled with statistics enabled). This pid is not for sending unix signals, use the pid from nsd.pid for that, that pid is also stable. .TP .B verbosity Change logging verbosity. .SH "EXIT CODE" The nsd\-control program exits with status code 1 on error, 0 on success. .SH "SET UP" The setup requires a self\-signed certificate and private keys for both the server and client. The script \fInsd\-control\-setup\fR generates these in the default run directory, or with \-d in another directory. If you change the access control permissions on the key files you can decide who can use nsd\-control, by default owner and group but not all users. The script preserves private keys present in the directory. After running the script as root, turn on \fBcontrol\-enable\fR in \fInsd.conf\fR. .SH "STATISTIC COUNTERS" The \fIstats\fR command shows a number of statistic counters. .TP .I num.queries number of queries received (the tcp and udp queries added up). .TP .I serverX.queries number of queries handled by the server process. The number of server processes is set with the config statement \fBserver\-count\fR. .TP .I time.boot uptime in seconds since the server was started. With fractional seconds. .TP .I time.elapsed time since the last stats report, in seconds. With fractional seconds. Can be zero if polled quickly and the previous stats command resets the counters, so that the next gets a fully zero, and zero elapsed time, report. .TP .I size.db.disk size of nsd.db on disk, in bytes. .TP .I size.db.mem size of the DNS database in memory, in bytes. .TP .I size.xfrd.mem size of memory for zone transfers and notifies in xfrd process, excludes TSIG data, in bytes. .TP .I size.config.disk size of zonelist file on disk, excludes the nsd.conf size, in bytes. .TP .I size.config.mem size of config data in memory, kept twice in server and xfrd process, in bytes. .TP .I num.type.X number of queries with this query type. .TP .I num.opcode.X number of queries with this opcode. .TP .I num.class.X number of queries with this query class. .TP .I num.rcode.X number of answers that carried this return code. .TP .I num.edns number of queries with EDNS OPT. .TP .I num.ednserr number of queries which failed EDNS parse. .TP .I num.udp number of queries over UDP ip4. .TP .I num.udp6 number of queries over UDP ip6. .TP .I num.tcp number of connections over TCP ip4. .TP .I num.tcp6 number of connections over TCP ip6. .TP .I num.answer_wo_aa number of answers with NOERROR rcode and without AA flag, this includes the referrals. .TP .I num.rxerr number of queries for which the receive failed. .TP .I num.txerr number of answers for which the transmit failed. .TP .I num.raxfr number of AXFR requests from clients (that got served with reply). .TP .I num.truncated number of answers with TC flag set. .TP .I num.dropped number of queries that were dropped because they failed sanity check. .TP .I zone.master number of master zones served. These are zones with no 'request\-xfr:' entries. .TP .I zone.slave number of slave zones served. These are zones with 'request\-xfr' entries. .SH "FILES" .TP .I @nsdconfigfile@ nsd configuration file. .TP .I @configdir@ directory with private keys (nsd_server.key and nsd_control.key) and self\-signed certificates (nsd_server.pem and nsd_control.pem). .SH "SEE ALSO" \fInsd.conf\fR(5), \fInsd\fR(8), \fInsd\-checkconf\fR(8) nsd-4.1.26/options.h0000664000175000017500000003256713355422740013714 0ustar wouterwouter/* * options.h -- nsd.conf options definitions and prototypes * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef OPTIONS_H #define OPTIONS_H #include "config.h" #include #include "region-allocator.h" #include "rbtree.h" struct query; struct dname; struct tsig_key; struct buffer; struct nsd; typedef struct nsd_options nsd_options_type; typedef struct pattern_options pattern_options_type; typedef struct zone_options zone_options_type; typedef struct ip_address_option ip_address_option_type; typedef struct acl_options acl_options_type; typedef struct key_options key_options_type; typedef struct config_parser_state config_parser_state_type; /* * Options global for nsd. */ struct nsd_options { /* config file name */ char* configfile; /* options for zones, by apex, contains zone_options */ rbtree_type* zone_options; /* patterns, by name, contains pattern_options */ rbtree_type* patterns; /* free space in zonelist file, contains zonelist_bucket */ rbtree_type* zonefree; /* number of free space lines in zonelist file */ size_t zonefree_number; /* zonelist file if open */ FILE* zonelist; /* last offset in file (or 0 if none) */ off_t zonelist_off; /* tree of zonestat names and their id values, entries are struct * zonestatname with malloced key=stringname. The number of items * is the max statnameid, no items are freed from this. * kept correct in the xfrd process, and on startup. */ rbtree_type* zonestatnames; /* rbtree of keys defined, by name */ rbtree_type* keys; /* list of ip addresses to bind to (or NULL for all) */ struct ip_address_option* ip_addresses; int ip_transparent; int ip_freebind; int debug_mode; int verbosity; int hide_version; int do_ip4; int do_ip6; const char* database; const char* identity; const char* version; const char* logfile; int server_count; int tcp_count; int tcp_query_count; int tcp_timeout; int tcp_mss; int outgoing_tcp_mss; size_t ipv4_edns_size; size_t ipv6_edns_size; const char* pidfile; const char* port; int statistics; const char* chroot; const char* username; const char* zonesdir; const char* xfrdfile; const char* xfrdir; const char* zonelistfile; const char* nsid; int xfrd_reload_timeout; int zonefiles_check; int zonefiles_write; int log_time_ascii; int round_robin; int minimal_responses; int refuse_any; int reuseport; /** remote control section. enable toggle. */ int control_enable; /** the interfaces the remote control should listen on */ struct ip_address_option* control_interface; /** port number for the control port */ int control_port; /** private key file for server */ char* server_key_file; /** certificate file for server */ char* server_cert_file; /** private key file for nsd-control */ char* control_key_file; /** certificate file for nsd-control */ char* control_cert_file; #ifdef RATELIMIT /** number of buckets in rrl hashtable */ size_t rrl_size; /** max qps for queries, 0 is nolimit */ size_t rrl_ratelimit; /** ratio of slipped responses, 0 is noslip */ size_t rrl_slip; /** ip prefix length */ size_t rrl_ipv4_prefix_length; size_t rrl_ipv6_prefix_length; /** max qps for whitelisted queries, 0 is nolimit */ size_t rrl_whitelist_ratelimit; #endif /** if dnstap is enabled */ int dnstap_enable; /** dnstap socket path */ char* dnstap_socket_path; /** true to send "identity" via dnstap */ int dnstap_send_identity; /** true to send "version" via dnstap */ int dnstap_send_version; /** dnstap "identity", hostname is used if "". */ char* dnstap_identity; /** dnstap "version", package version is used if "". */ char* dnstap_version; /** true to log dnstap AUTH_QUERY message events */ int dnstap_log_auth_query_messages; /** true to log dnstap AUTH_RESPONSE message events */ int dnstap_log_auth_response_messages; region_type* region; }; struct ip_address_option { struct ip_address_option* next; char* address; }; /* * Pattern of zone options, used to contain options for zone(s). */ struct pattern_options { rbnode_type node; const char* pname; /* name of the pattern, key of rbtree */ const char* zonefile; struct acl_options* allow_notify; struct acl_options* request_xfr; struct acl_options* notify; struct acl_options* provide_xfr; struct acl_options* outgoing_interface; const char* zonestats; #ifdef RATELIMIT uint16_t rrl_whitelist; /* bitmap with rrl types */ #endif uint8_t allow_axfr_fallback; uint8_t allow_axfr_fallback_is_default; uint8_t notify_retry; uint8_t notify_retry_is_default; uint8_t implicit; /* pattern is implicit, part_of_config zone used */ uint8_t xfrd_flags; uint32_t max_refresh_time; uint8_t max_refresh_time_is_default; uint32_t min_refresh_time; uint8_t min_refresh_time_is_default; uint32_t max_retry_time; uint8_t max_retry_time_is_default; uint32_t min_retry_time; uint8_t min_retry_time_is_default; uint64_t size_limit_xfr; uint8_t multi_master_check; } ATTR_PACKED; #define PATTERN_IMPLICIT_MARKER "_implicit_" /* * Options for a zone */ struct zone_options { /* key is dname of apex */ rbnode_type node; /* is apex of the zone */ const char* name; /* if not part of config, the offset and linesize of zonelist entry */ off_t off; int linesize; /* pattern for the zone options, if zone is part_of_config, this is * a anonymous pattern created in-place */ 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 struct in_addr addr; struct in6_addr addr6; #else struct in_addr addr; #endif }; /* * Access control list element */ struct acl_options { struct acl_options* next; /* options */ time_t ixfr_disabled; int bad_xfr_count; uint8_t use_axfr_only; uint8_t allow_udp; /* ip address range */ const char* ip_address_spec; uint8_t is_ipv6; unsigned int port; /* is 0(no port) or suffix @port value */ union acl_addr_storage addr; union acl_addr_storage range_mask; enum { acl_range_single = 0, /* single address */ acl_range_mask = 1, /* 10.20.30.40&255.255.255.0 */ acl_range_subnet = 2, /* 10.20.30.40/28 */ acl_range_minmax = 3 /* 10.20.30.40-10.20.30.60 (mask=max) */ } rangetype; /* key */ uint8_t nokey; uint8_t blocked; const char* key_name; struct key_options* key_options; } ATTR_PACKED; /* * Key definition */ struct key_options { rbnode_type node; /* key of tree is name */ char* name; char* algorithm; char* secret; struct tsig_key* tsig_key; } ATTR_PACKED; /** zone list free space */ struct zonelist_free { struct zonelist_free* next; off_t off; }; /** zonelist free bucket for a particular line length */ struct zonelist_bucket { rbnode_type node; /* key is ptr to linesize */ int linesize; struct zonelist_free* list; }; /* default zonefile write interval if database is "", in seconds */ #define ZONEFILES_WRITE_INTERVAL 3600 struct zonestatname { rbnode_type node; /* key is malloced string with cooked zonestat name */ unsigned id; /* index in nsd.zonestat array */ }; /* * Used during options parsing */ struct config_parser_state { char* filename; const char* chroot; int line; int errors; int server_settings_seen; struct nsd_options* opt; struct pattern_options* current_pattern; struct zone_options* current_zone; struct key_options* current_key; struct ip_address_option* current_ip_address_option; struct acl_options* current_allow_notify; struct acl_options* current_request_xfr; struct acl_options* current_notify; struct acl_options* current_provide_xfr; struct acl_options* current_outgoing_interface; void (*err)(void*,const char*); void* err_arg; }; extern config_parser_state_type* cfg_parser; /* region will be put in nsd_options struct. Returns empty options struct. */ struct nsd_options* nsd_options_create(region_type* region); /* the number of zones that are configured */ static inline size_t nsd_options_num_zones(struct nsd_options* opt) { return opt->zone_options->count; } /* insert a zone into the main options tree, returns 0 on error */ int nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone); /* insert a pattern into the main options tree, returns 0 on error */ int nsd_options_insert_pattern(struct nsd_options* opt, struct pattern_options* pat); /* parses options file. Returns false on failure. callback, if nonNULL, * gets called with error strings, default prints. */ int parse_options_file(struct nsd_options* opt, const char* file, void (*err)(void*,const char*), void* err_arg); struct zone_options* zone_options_create(region_type* region); void zone_options_delete(struct nsd_options* opt, struct zone_options* zone); /* find a zone by apex domain name, or NULL if not found. */ struct zone_options* zone_options_find(struct nsd_options* opt, const struct dname* apex); struct pattern_options* pattern_options_create(region_type* region); struct pattern_options* pattern_options_find(struct nsd_options* opt, const char* name); int pattern_options_equal(struct pattern_options* p, struct pattern_options* q); void pattern_options_remove(struct nsd_options* opt, const char* name); void pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p); void pattern_options_marshal(struct buffer* buffer, struct pattern_options* p); struct pattern_options* pattern_options_unmarshal(region_type* r, struct buffer* b); struct key_options* key_options_create(region_type* region); void key_options_insert(struct nsd_options* opt, struct key_options* key); struct key_options* key_options_find(struct nsd_options* opt, const char* name); void key_options_remove(struct nsd_options* opt, const char* name); int key_options_equal(struct key_options* p, struct key_options* q); void key_options_add_modify(struct nsd_options* opt, struct key_options* key); /* read in zone list file. Returns false on failure */ int parse_zone_list_file(struct nsd_options* opt); /* create zone entry and add to the zonelist file */ struct zone_options* zone_list_add(struct nsd_options* opt, const char* zname, const char* pname); /* create zonelist entry, do not insert in file (called by _add) */ struct zone_options* zone_list_zone_insert(struct nsd_options* opt, const char* nm, const char* patnm, int linesize, off_t off); void zone_list_del(struct nsd_options* opt, struct zone_options* zone); void zone_list_compact(struct nsd_options* opt); void zone_list_close(struct nsd_options* opt); /* create zonestat name tree , for initially created zones */ void options_zonestatnames_create(struct nsd_options* opt); /* Get zonestat id for zone options, add new entry if necessary. * instantiates the pattern's zonestat string */ unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt); /* create string, same options as zonefile but no chroot changes */ const char* config_cook_string(struct zone_options* zone, const char* input); /** check if config for remote control turns on IP-address interface * with certificates or a named pipe without certificates. */ int options_remote_is_address(struct nsd_options* cfg); #if defined(HAVE_SSL) /* tsig must be inited, adds all keys in options to tsig. */ void key_options_tsig_add(struct nsd_options* opt); #endif /* check acl list, acl number that matches if passed(0..), * or failure (-1) if dropped */ /* the reason why (the acl) is returned too (or NULL) */ int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason); int acl_addr_matches_host(struct acl_options* acl, struct acl_options* host); int acl_addr_matches(struct acl_options* acl, struct query* q); int acl_key_matches(struct acl_options* acl, struct query* q); int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz); int acl_addr_match_range(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz); /* returns true if acls are both from the same host */ int acl_same_host(struct acl_options* a, struct acl_options* b); /* find acl by number in the list */ struct acl_options* acl_find_num(struct acl_options* acl, int num); /* see if two acl lists are the same (same elements in same order, or empty) */ int acl_list_equal(struct acl_options* p, struct acl_options* q); /* see if two acl are the same */ int acl_equal(struct acl_options* p, struct acl_options* q); /* see if a zone is a slave or a master zone */ int zone_is_slave(struct zone_options* opt); /* create zonefile name, returns static pointer (perhaps to options data) */ const char* config_make_zonefile(struct zone_options* zone, struct nsd* nsd); #define ZONEC_PCT_TIME 5 /* seconds, then it starts to print pcts */ #define ZONEC_PCT_COUNT 100000 /* elements before pct check is done */ /* parsing helpers */ void c_error(const char* msg); void c_error_msg(const char* fmt, ...) ATTR_FORMAT(printf, 1, 2); struct acl_options* parse_acl_info(region_type* region, char* ip, const char* key); /* true if ipv6 address, false if ipv4 */ int parse_acl_is_ipv6(const char* p); /* returns range type. mask is the 2nd part of the range */ int parse_acl_range_type(char* ip, char** mask); /* parses subnet mask, fills 0 mask as well */ void parse_acl_range_subnet(char* p, void* addr, int maxbits); /* clean up options */ void nsd_options_destroy(struct nsd_options* opt); /* replace occurrences of one with two in buf, pass length of buffer */ void replace_str(char* buf, size_t len, const char* one, const char* two); /* apply pattern to the existing pattern in the parser */ void config_apply_pattern(const char* name); #endif /* OPTIONS_H */ nsd-4.1.26/nsd.8.in0000664000175000017500000001266013401455025013314 0ustar wouterwouter.TH "NSD" "8" "Dec 4, 2018" "NLnet Labs" "NSD 4.1.26" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd \- Name Server Daemon (NSD) version 4.1.26. .SH "SYNOPSIS" .B nsd .RB [ \-4 ] .RB [ \-6 ] .RB [ \-a .IR ip\-address[@port] ] .RB [ \-c .IR configfile ] .RB [ \-d ] .RB [ \-f .IR database ] .RB [ \-h ] .RB [ \-i .IR identity ] .RB [ \-I .IR nsid ] .RB [ \-l .IR logfile ] .RB [ \-N .IR server\-count ] .RB [ \-n .IR noncurrent\-tcp\-count ] .RB [ \-P .IR pidfile ] .RB [ \-p .IR port ] .RB [ \-s .IR seconds ] .RB [ \-t .IR chrootdir ] .RB [ \-u .IR username ] .RB [ \-V .IR level ] .RB [ \-v ] .SH "DESCRIPTION" .B NSD is a complete implementation of an authoritative DNS nameserver. Upon startup, .B NSD will read the database specified with .B \-f .I database argument and put itself into background and answers queries on port 53 or a different port specified with .B \-p .I port option. The .I database is created if it does not exist. By default, .B NSD will bind to all local interfaces available. Use the .B \-a .I ip\-address[@port] option to specify a single particular interface address to be bound. If this option is given more than once, .B NSD will bind its UDP and TCP sockets to all the specified ip\-addresses separately. If IPv6 is enabled when .B NSD is compiled an IPv6 address can also be specified. .P .SH "OPTIONS" All the options can be specified in the configfile ( .B \-c argument), except for the .B \-v and .B \-h options. If options are specified on the commandline, the options on the commandline take precedence over the options in the configfile. .P Normally .B NSD should be started with the `nsd\-control(8) start` command invoked from a .I /etc/rc.d/nsd.sh script or similar at the operating system startup. .TP .B \-4 Only listen to IPv4 connections. .TP .B \-6 Only listen to IPv6 connections. .TP .B \-a\fI ip\-address[@port] Listen to the specified .IR ip\-address . The .I ip\-address must be specified in numeric format (using the standard IPv4 or IPv6 notation). Optionally, a port number can be given. This flag can be specified multiple times to listen to multiple IP addresses. If this flag is not specified, .B NSD listens to the wildcard interface. .TP .B \-c\fI configfile Read specified .I configfile instead of the default .IR @nsdconfigfile@ . For format description see nsd.conf(5). .TP .B \-d Do not fork, stay in the foreground. .TP .B \-f\fI database Use the specified .I database instead of the default of .IR '@dbfile@' . If a .B zonesdir: is specified in the config file this path can be relative to that directory. .TP .B \-h Print help information and exit. .TP .B \-i\fI identity Return the specified .I identity when asked for .I CH TXT ID.SERVER (This option is used to determine which server is answering the queries when they are anycast). The default is the name returned by gethostname(3). .TP .B \-I\fI nsid Add the specified .I nsid to the EDNS section of the answer when queried with an NSID EDNS enabled packet. As a sequence of hex characters or with ascii_ prefix and then an ascii string. .TP .B \-l\fI logfile Log messages to the specified .IR logfile . The default is to log to stderr and syslog. If a .B zonesdir: is specified in the config file this path can be relative to that directory. .TP .B \-N\fI count Start .I count .B NSD servers. The default is 1. Starting more than a single server is only useful on machines with multiple CPUs and/or network adapters. .TP .B \-n\fI number The maximum .I number of concurrent TCP connection that can be handled by each server. The default is 100. .TP .B \-P\fI pidfile Use the specified .I pidfile instead of the platform specific default, which is mostly .IR @pidfile@ . If a .B zonesdir: is specified in the config file, this path can be relative to that directory. .TP .B \-p\fI port Answer the queries on the specified .IR port . Normally this is port 53. .TP .B \-s\fI seconds Produce statistics dump every .I seconds seconds. This is equal to sending .I SIGUSR1 to the daemon periodically. .TP .B \-t\fI chroot Specifies a directory to .I chroot to upon startup. This option requires you to ensure that appropriate syslogd(8) socket (e.g. .I chrootdir /dev/log) is available, otherwise .B NSD won't produce any log output. .TP .B \-u\fI username Drop user and group privileges to those of .I username after binding the socket. The .I username must be one of: username, id, or id.gid. For example: nsd, 80, or 80.80. .TP .B \-V\fI level This value specifies the verbosity level for (non\-debug) logging. Default is 0. .TP .B \-v Print the version number of .B NSD to standard error and exit. .LP .B NSD reacts to the following signals: .TP SIGTERM Stop answering queries, shutdown, and exit normally. .TP SIGHUP Reload. Scans zone files and if changed (mtime) reads them in. Also reopens the logfile (assists logrotation). .TP SIGUSR1 Dump BIND8\-style statistics into the log. Ignored otherwise. .SH "FILES" .TP "@dbfile@" default .B NSD database .TP @pidfile@ the process id of the name server. .TP @nsdconfigfile@ default .B NSD configuration file .SH "DIAGNOSTICS" .B NSD will log all the problems via the standard syslog(8) .I daemon facility, unless the .B \-d option is specified. .SH "SEE ALSO" \fInsd.conf\fR(5), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. nsd-4.1.26/netio.c0000664000175000017500000001462613167336742013335 0ustar wouterwouter/* * netio.c -- network I/O support. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "netio.h" #include "util.h" #define MAX_NETIO_FDS 1024 netio_type * netio_create(region_type *region) { netio_type *result; assert(region); result = (netio_type *) region_alloc(region, sizeof(netio_type)); result->region = region; result->handlers = NULL; result->deallocated = NULL; result->dispatch_next = NULL; return result; } void netio_add_handler(netio_type *netio, netio_handler_type *handler) { netio_handler_list_type *elt; assert(netio); assert(handler); if (netio->deallocated) { /* * If we have deallocated handler list elements, reuse * the first one. */ elt = netio->deallocated; netio->deallocated = elt->next; } else { /* * Allocate a new one. */ elt = (netio_handler_list_type *) region_alloc( netio->region, sizeof(netio_handler_list_type)); } elt->next = netio->handlers; elt->handler = handler; elt->handler->pfd = -1; netio->handlers = elt; } void netio_remove_handler(netio_type *netio, netio_handler_type *handler) { netio_handler_list_type **elt_ptr; assert(netio); assert(handler); for (elt_ptr = &netio->handlers; *elt_ptr; elt_ptr = &(*elt_ptr)->next) { if ((*elt_ptr)->handler == handler) { netio_handler_list_type *next = (*elt_ptr)->next; if ((*elt_ptr) == netio->dispatch_next) netio->dispatch_next = next; (*elt_ptr)->handler = NULL; (*elt_ptr)->next = netio->deallocated; netio->deallocated = *elt_ptr; *elt_ptr = next; break; } } } const struct timespec * netio_current_time(netio_type *netio) { assert(netio); if (!netio->have_current_time) { struct timeval current_timeval; if (gettimeofday(¤t_timeval, NULL) == -1) { log_msg(LOG_ERR, "gettimeofday: %s, aborting.", strerror(errno)); abort(); } timeval_to_timespec(&netio->cached_current_time, ¤t_timeval); netio->have_current_time = 1; } return &netio->cached_current_time; } int netio_dispatch(netio_type *netio, const struct timespec *timeout, const sigset_t *sigmask) { /* static arrays to avoid allocation */ static struct pollfd fds[MAX_NETIO_FDS]; int numfd; int have_timeout = 0; struct timespec minimum_timeout; netio_handler_type *timeout_handler = NULL; netio_handler_list_type *elt; int rc; int result = 0; #ifndef HAVE_PPOLL sigset_t origmask; #endif assert(netio); /* * Clear the cached current time. */ netio->have_current_time = 0; /* * Initialize the minimum timeout with the timeout parameter. */ if (timeout) { have_timeout = 1; memcpy(&minimum_timeout, timeout, sizeof(struct timespec)); } /* * Initialize the fd_sets and timeout based on the handler * information. */ numfd = 0; for (elt = netio->handlers; elt; elt = elt->next) { netio_handler_type *handler = elt->handler; if (handler->fd != -1 && numfd < MAX_NETIO_FDS) { fds[numfd].fd = handler->fd; fds[numfd].events = 0; fds[numfd].revents = 0; handler->pfd = numfd; if (handler->event_types & NETIO_EVENT_READ) { fds[numfd].events |= POLLIN; } if (handler->event_types & NETIO_EVENT_WRITE) { fds[numfd].events |= POLLOUT; } numfd++; } else { handler->pfd = -1; } if (handler->timeout && (handler->event_types & NETIO_EVENT_TIMEOUT)) { struct timespec relative; relative.tv_sec = handler->timeout->tv_sec; relative.tv_nsec = handler->timeout->tv_nsec; timespec_subtract(&relative, netio_current_time(netio)); if (!have_timeout || timespec_compare(&relative, &minimum_timeout) < 0) { have_timeout = 1; minimum_timeout.tv_sec = relative.tv_sec; minimum_timeout.tv_nsec = relative.tv_nsec; timeout_handler = handler; } } } if (have_timeout && minimum_timeout.tv_sec < 0) { /* * On negative timeout for a handler, immediately * dispatch the timeout event without checking for * other events. */ if (timeout_handler && (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) { timeout_handler->event_handler(netio, timeout_handler, NETIO_EVENT_TIMEOUT); } return result; } /* Check for events. */ #ifdef HAVE_PPOLL rc = ppoll(fds, numfd, (have_timeout?&minimum_timeout:NULL), sigmask); #else sigprocmask(SIG_SETMASK, sigmask, &origmask); rc = poll(fds, numfd, (have_timeout?minimum_timeout.tv_sec*1000+ minimum_timeout.tv_nsec/1000000:-1)); sigprocmask(SIG_SETMASK, &origmask, NULL); #endif /* HAVE_PPOLL */ if (rc == -1) { if(errno == EINVAL || errno == EACCES || errno == EBADF) { log_msg(LOG_ERR, "fatal error poll: %s.", strerror(errno)); exit(1); } return -1; } /* * Clear the cached current_time (pselect(2) may block for * some time so the cached value is likely to be old). */ netio->have_current_time = 0; if (rc == 0) { /* * No events before the minimum timeout expired. * Dispatch to handler if interested. */ if (timeout_handler && (timeout_handler->event_types & NETIO_EVENT_TIMEOUT)) { timeout_handler->event_handler(netio, timeout_handler, NETIO_EVENT_TIMEOUT); } } else { /* * Dispatch all the events to interested handlers * based on the fd_sets. Note that a handler might * deinstall itself, so store the next handler before * calling the current handler! */ assert(netio->dispatch_next == NULL); for (elt = netio->handlers; elt && rc; ) { netio_handler_type *handler = elt->handler; netio->dispatch_next = elt->next; if (handler->fd != -1 && handler->pfd != -1) { netio_event_types_type event_types = NETIO_EVENT_NONE; if ((fds[handler->pfd].revents & POLLIN)) { event_types |= NETIO_EVENT_READ; } if ((fds[handler->pfd].revents & POLLOUT)) { event_types |= NETIO_EVENT_WRITE; } if ((fds[handler->pfd].revents & (POLLNVAL|POLLHUP|POLLERR))) { /* closed/error: give a read event, * or otherwise, a write event */ if((handler->event_types&NETIO_EVENT_READ)) event_types |= NETIO_EVENT_READ; else if((handler->event_types&NETIO_EVENT_WRITE)) event_types |= NETIO_EVENT_WRITE; } if (event_types & handler->event_types) { handler->event_handler(netio, handler, event_types & handler->event_types); ++result; } } elt = netio->dispatch_next; } netio->dispatch_next = NULL; } return result; } nsd-4.1.26/nsd-control.c0000664000175000017500000003445413376764073014466 0ustar wouterwouter/* * nsd-control.c - remote control utility for nsd. * * Copyright (c) 2011, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * The remote control utility contacts the nsd server over ssl and * sends the command, receives the answer, and displays the result * from the commandline. */ #include "config.h" #ifdef HAVE_SSL #include #include #include #ifdef HAVE_OPENSSL_SSL_H #include #endif #ifdef HAVE_OPENSSL_ERR_H #include #endif #ifdef HAVE_OPENSSL_RAND_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif #include "util.h" #include "tsig.h" #include "options.h" static void usage() ATTR_NORETURN; static void ssl_err(const char* s) ATTR_NORETURN; static void ssl_path_err(const char* s, const char *path) ATTR_NORETURN; /** Give nsd-control usage, and exit (1). */ static void usage() { printf("Usage: nsd-control [options] command\n"); printf(" Remote control utility for nsd server.\n"); printf("Version %s. Report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); printf("Options:\n"); printf(" -c file config file, default is %s\n", CONFIGFILE); printf(" -s ip[@port] server address, if omitted config is used.\n"); printf(" -h show this usage help.\n"); printf("Commands:\n"); printf(" start start server; runs nsd(8)\n"); printf(" stop stops the server\n"); printf(" reload [] reload modified zonefiles from disk\n"); printf(" reconfig reload the config file\n"); printf(" repattern the same as reconfig\n"); printf(" log_reopen reopen logfile (for log rotate)\n"); printf(" status display status of server\n"); printf(" stats print statistics\n"); printf(" stats_noreset peek at statistics\n"); printf(" addzone add a new zone\n"); printf(" delzone remove a zone\n"); printf(" changezone change zone to use pattern\n"); printf(" addzones add zone list on stdin {name space pattern newline}\n"); printf(" delzones remove zone list on stdin {name newline}\n"); printf(" write [] write changed zonefiles to disk\n"); printf(" notify [] send NOTIFY messages to slave servers\n"); printf(" transfer [] try to update slave zones to newer serial\n"); printf(" force_transfer [] update slave zones with AXFR, no serial check\n"); printf(" zonestatus [] print state, serial, activity\n"); printf(" serverpid get pid of server process\n"); printf(" verbosity change logging detail\n"); exit(1); } /** exit with ssl error */ static void ssl_err(const char* s) { fprintf(stderr, "error: %s\n", s); ERR_print_errors_fp(stderr); exit(1); } /** exit with ssl error related to a file path */ static void ssl_path_err(const char* s, const char *path) { unsigned long err; err = ERR_peek_error(); if (ERR_GET_LIB(err) == ERR_LIB_SYS && (ERR_GET_FUNC(err) == SYS_F_FOPEN || ERR_GET_FUNC(err) == SYS_F_FREAD) ) { fprintf(stderr, "error: %s\n%s: %s\n", s, path, ERR_reason_error_string(err)); exit(1); } else { ssl_err(s); } } /** setup SSL context */ static SSL_CTX* setup_ctx(struct nsd_options* cfg) { char* s_cert, *c_key, *c_cert; SSL_CTX* ctx; if(!options_remote_is_address(cfg)) return NULL; s_cert = cfg->server_cert_file; c_key = cfg->control_key_file; c_cert = cfg->control_cert_file; /* filenames may be relative to zonesdir */ if (cfg->zonesdir && cfg->zonesdir[0] && (s_cert[0] != '/' || c_key[0] != '/' || c_cert[0] != '/')) { if(chdir(cfg->zonesdir)) error("could not chdir to zonesdir: %s %s", cfg->zonesdir, strerror(errno)); } ctx = SSL_CTX_new(SSLv23_client_method()); if(!ctx) ssl_err("could not allocate SSL_CTX pointer"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2) ssl_err("could not set SSL_OP_NO_SSLv2"); if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client cert", c_cert); if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)) ssl_path_err("Error setting up SSL_CTX client key", c_key); if(!SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key"); if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) ssl_path_err("Error setting up SSL_CTX verify, server cert", s_cert); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); return ctx; } /** contact the server with TCP connect */ static int contact_server(const char* svr, struct nsd_options* cfg, int statuscmd) { #ifdef INET6 struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen; int fd; int port = cfg->control_port; int addrfamily = 0; /* use svr or a config entry */ if(!svr) { if(cfg->control_interface) { svr = cfg->control_interface->address; } else if(cfg->do_ip4) { svr = "127.0.0.1"; } else { svr = "::1"; } /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; else if(strcmp(svr, "::0") == 0 || strcmp(svr, "0::0") == 0 || strcmp(svr, "0::") == 0 || strcmp(svr, "::") == 0) svr = "::1"; } if(strchr(svr, '@')) { char* ps = strchr(svr, '@'); *ps++ = 0; port = atoi(ps); if(!port) { fprintf(stderr, "could not parse port %s\n", ps); exit(1); } } if(svr[0] == '/') { #ifdef HAVE_SYS_UN_H struct sockaddr_un* usock = (struct sockaddr_un *) &addr; usock->sun_family = AF_LOCAL; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN usock->sun_len = (unsigned)sizeof(usock); #endif (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); addrlen = (socklen_t)sizeof(struct sockaddr_un); addrfamily = AF_LOCAL; port = 0; #endif } else if(strchr(svr, ':')) { struct sockaddr_in6 sa; addrlen = (socklen_t)sizeof(struct sockaddr_in6); memset(&sa, 0, addrlen); sa.sin6_family = AF_INET6; sa.sin6_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin6_family, svr, &sa.sin6_addr) <= 0) { fprintf(stderr, "could not parse IP: %s\n", svr); exit(1); } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET6; } else { /* ip4 */ struct sockaddr_in sa; addrlen = (socklen_t)sizeof(struct sockaddr_in); memset(&sa, 0, addrlen); sa.sin_family = AF_INET; sa.sin_port = (in_port_t)htons((uint16_t)port); if(inet_pton((int)sa.sin_family, svr, &sa.sin_addr) <= 0) { fprintf(stderr, "could not parse IP: %s\n", svr); exit(1); } memcpy(&addr, &sa, addrlen); addrfamily = AF_INET; } fd = socket(addrfamily, SOCK_STREAM, 0); if(fd == -1) { fprintf(stderr, "socket: %s\n", strerror(errno)); exit(1); } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { int err = errno; if(!port) fprintf(stderr, "error: connect (%s): %s\n", svr, strerror(err)); else fprintf(stderr, "error: connect (%s@%d): %s\n", svr, port, strerror(err)); if(err == ECONNREFUSED && statuscmd) { printf("nsd is stopped\n"); exit(3); } exit(1); } return fd; } /** setup SSL on the connection */ static SSL* setup_ssl(SSL_CTX* ctx, int fd) { SSL* ssl; X509* x; int r; if(!ctx) return NULL; ssl = SSL_new(ctx); if(!ssl) ssl_err("could not SSL_new"); SSL_set_connect_state(ssl); (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(ssl, fd)) ssl_err("could not SSL_set_fd"); while(1) { ERR_clear_error(); if( (r=SSL_do_handshake(ssl)) == 1) break; r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) ssl_err("SSL handshake failed"); /* wants to be called again */ } /* check authenticity of server */ if(SSL_get_verify_result(ssl) != X509_V_OK) ssl_err("SSL verification failed"); x = SSL_get_peer_certificate(ssl); if(!x) ssl_err("Server presented no peer certificate"); X509_free(x); return ssl; } /** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ static int remote_read(SSL* ssl, int fd, char* buf, size_t len) { if(ssl) { int r; ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ return 0; } ssl_err("could not SSL_read"); } buf[r] = 0; } else { ssize_t rr = read(fd, buf, len-1); if(rr <= 0) { if(rr == 0) { /* EOF */ return 0; } fprintf(stderr, "could not read: %s\n", strerror(errno)); exit(1); } buf[rr] = 0; } return 1; } /** write to ssl or fd, fatalexit on error */ static void remote_write(SSL* ssl, int fd, const char* buf, size_t len) { if(ssl) { if(SSL_write(ssl, buf, (int)len) <= 0) ssl_err("could not SSL_write"); } else { if(write(fd, buf, len) < (ssize_t)len) { fprintf(stderr, "could not write: %s\n", strerror(errno)); exit(1); } } } /** send stdin to server */ static void send_file(SSL* ssl, int fd, FILE* in, char* buf, size_t sz) { char e[] = {0x04, 0x0a}; while(fgets(buf, (int)sz, in)) { remote_write(ssl, fd, buf, strlen(buf)); } /* send end-of-file marker */ remote_write(ssl, fd, e, sizeof(e)); } /** send command and display result */ static int go_cmd(SSL* ssl, int fd, int argc, char* argv[]) { char pre[10]; const char* space=" "; const char* newline="\n"; int was_error = 0, first_line = 1; int i; char buf[1024]; snprintf(pre, sizeof(pre), "NSDCT%d ", NSD_CONTROL_VERSION); remote_write(ssl, fd, pre, strlen(pre)); for(i=0; iregion); if(!parse_options_file(opt, cfgfile, NULL, NULL)) { fprintf(stderr, "could not read config file\n"); exit(1); } if(!opt->control_enable) fprintf(stderr, "warning: control-enable is 'no' in the config file.\n"); ctx = setup_ctx(opt); /* contact server */ fd = contact_server(svr, opt, argc>0&&strcmp(argv[0],"status")==0); ssl = setup_ssl(ctx, fd); /* send command */ ret = go_cmd(ssl, fd, argc, argv); if(ssl) SSL_free(ssl); close(fd); if(ctx) SSL_CTX_free(ctx); region_destroy(opt->region); return ret; } /** 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 routine for nsd-control */ int main(int argc, char* argv[]) { int c; const char* cfgfile = CONFIGFILE; char* svr = NULL; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif log_init("nsd-control"); #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); #endif ERR_load_SSL_strings(); #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else OPENSSL_init_ssl(0, NULL); #endif if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); size_t i; v = seed; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); fprintf(stderr, "warning: no entropy, seeding openssl PRNG with time\n"); } /* parse the options */ while( (c=getopt(argc, argv, "c:s:h")) != -1) { switch(c) { case 'c': cfgfile = optarg; break; case 's': svr = optarg; break; case '?': case 'h': default: usage(); } } argc -= optind; argv += optind; if(argc == 0) usage(); if(argc >= 1 && strcmp(argv[0], "start")==0) { if(execl(NSD_START_PATH, "nsd", "-c", cfgfile, (char*)NULL) < 0) { fprintf(stderr, "could not exec %s: %s\n", NSD_START_PATH, strerror(errno)); exit(1); } } return go(cfgfile, svr, argc, argv); } #else /* HAVE_SSL */ int main(void) { printf("error: NSD was compiled without SSL.\n"); return 1; } #endif /* HAVE_SSL */ nsd-4.1.26/util.c0000664000175000017500000006021113345735143013157 0ustar wouterwouter/* * util.c -- set of various support routines. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG_H #include #endif /* HAVE_SYSLOG_H */ #include #include "util.h" #include "region-allocator.h" #include "dname.h" #include "namedb.h" #include "rdata.h" #include "zonec.h" #ifdef USE_MMAP_ALLOC #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #elif defined(MAP_ANONYMOUS) && !defined(MAP_ANON) #define MAP_ANON MAP_ANONYMOUS #endif #endif /* USE_MMAP_ALLOC */ #ifndef NDEBUG unsigned nsd_debug_facilities = 0xffff; int nsd_debug_level = 0; #endif #define MSB_32 0x80000000 int verbosity = 0; static const char *global_ident = NULL; static log_function_type *current_log_function = log_file; static FILE *current_log_file = NULL; int log_time_asc = 1; void log_init(const char *ident) { global_ident = ident; current_log_file = stderr; } void log_open(int option, int facility, const char *filename) { #ifdef HAVE_SYSLOG_H openlog(global_ident, option, facility); #endif /* HAVE_SYSLOG_H */ if (filename) { FILE *file = fopen(filename, "a"); if (!file) { log_msg(LOG_ERR, "Cannot open %s for appending (%s), " "logging to stderr", filename, strerror(errno)); } else { current_log_file = file; } } } void log_reopen(const char *filename, uint8_t verbose) { if (filename) { FILE *file; if(strcmp(filename, "/dev/stdout")==0 || strcmp(filename, "/dev/stderr")==0) return; file = fopen(filename, "a"); if (!file) { if (verbose) VERBOSITY(2, (LOG_WARNING, "Cannot reopen %s for appending (%s), " "keeping old logfile", filename, strerror(errno))); } else { if (current_log_file && current_log_file != stderr) fclose(current_log_file); current_log_file = file; } } } void log_finalize(void) { #ifdef HAVE_SYSLOG_H closelog(); #endif /* HAVE_SYSLOG_H */ if (current_log_file && current_log_file != stderr) { fclose(current_log_file); } current_log_file = NULL; } static lookup_table_type log_priority_table[] = { { LOG_ERR, "error" }, { LOG_WARNING, "warning" }, { LOG_NOTICE, "notice" }, { LOG_INFO, "info" }, { 0, NULL } }; void log_file(int priority, const char *message) { size_t length; lookup_table_type *priority_info; const char *priority_text = "unknown"; assert(global_ident); assert(current_log_file); priority_info = lookup_by_id(log_priority_table, priority); if (priority_info) { priority_text = priority_info->name; } /* Bug #104, add time_t timestamp */ #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) if(log_time_asc) { struct timeval tv; char tmbuf[32]; tmbuf[0]=0; tv.tv_usec = 0; if(gettimeofday(&tv, NULL) == 0) { struct tm tm; time_t now = (time_t)tv.tv_sec; strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", localtime_r(&now, &tm)); } fprintf(current_log_file, "[%s.%3.3d] %s[%d]: %s: %s", tmbuf, (int)tv.tv_usec/1000, global_ident, (int) getpid(), priority_text, message); } else #endif /* have time functions */ fprintf(current_log_file, "[%d] %s[%d]: %s: %s", (int)time(NULL), global_ident, (int) getpid(), priority_text, message); length = strlen(message); if (length == 0 || message[length - 1] != '\n') { fprintf(current_log_file, "\n"); } fflush(current_log_file); } void log_syslog(int priority, const char *message) { #ifdef HAVE_SYSLOG_H syslog(priority, "%s", message); #endif /* !HAVE_SYSLOG_H */ log_file(priority, message); } void log_set_log_function(log_function_type *log_function) { current_log_function = log_function; } void log_msg(int priority, const char *format, ...) { va_list args; va_start(args, format); log_vmsg(priority, format, args); va_end(args); } void log_vmsg(int priority, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; vsnprintf(message, sizeof(message), format, args); current_log_function(priority, message); } void set_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ bits[index / 8] |= (1 << (7 - index % 8)); } void clear_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ bits[index / 8] &= ~(1 << (7 - index % 8)); } int get_bit(uint8_t bits[], size_t index) { /* * The bits are counted from left to right, so bit #0 is the * left most bit. */ return bits[index / 8] & (1 << (7 - index % 8)); } lookup_table_type * lookup_by_name(lookup_table_type *table, const char *name) { while (table->name != NULL) { if (strcasecmp(name, table->name) == 0) return table; table++; } return NULL; } lookup_table_type * lookup_by_id(lookup_table_type *table, int id) { while (table->name != NULL) { if (table->id == id) return table; table++; } return NULL; } void * xalloc(size_t size) { void *result = malloc(size); if (!result) { log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); exit(1); } return result; } void * xmallocarray(size_t num, size_t size) { void *result = reallocarray(NULL, num, size); if (!result) { log_msg(LOG_ERR, "reallocarray failed: %s", strerror(errno)); exit(1); } return result; } void * xalloc_zero(size_t size) { void *result = calloc(1, size); if (!result) { log_msg(LOG_ERR, "calloc failed: %s", strerror(errno)); exit(1); } return result; } void * xalloc_array_zero(size_t num, size_t size) { void *result = calloc(num, size); if (!result) { log_msg(LOG_ERR, "calloc failed: %s", strerror(errno)); exit(1); } return result; } void * xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (!ptr) { log_msg(LOG_ERR, "realloc failed: %s", strerror(errno)); exit(1); } return ptr; } #ifdef USE_MMAP_ALLOC void * mmap_alloc(size_t size) { void *base; size += MMAP_ALLOC_HEADER_SIZE; #ifdef HAVE_MMAP base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (base == MAP_FAILED) { log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE_MMAP */ log_msg(LOG_ERR, "mmap failed: don't have mmap"); exit(1); #endif /* HAVE_MMAP */ *((size_t*) base) = size; return (void*)((uintptr_t)base + MMAP_ALLOC_HEADER_SIZE); } void mmap_free(void *ptr) { void *base; size_t size; if (!ptr) return; base = (void*)((uintptr_t)ptr - MMAP_ALLOC_HEADER_SIZE); size = *((size_t*) base); #ifdef HAVE_MUNMAP if (munmap(base, size) == -1) { log_msg(LOG_ERR, "munmap failed: %s", strerror(errno)); exit(1); } #else /* !HAVE_MUNMAP */ log_msg(LOG_ERR, "munmap failed: don't have munmap"); exit(1); #endif /* HAVE_MUNMAP */ } #endif /* USE_MMAP_ALLOC */ int write_data(FILE *file, const void *data, size_t size) { size_t result; if (size == 0) return 1; result = fwrite(data, 1, size, file); if (result == 0) { log_msg(LOG_ERR, "write failed: %s", strerror(errno)); return 0; } else if (result < size) { log_msg(LOG_ERR, "short write (disk full?)"); return 0; } else { return 1; } } int write_socket(int s, const void *buf, size_t size) { const char* data = (const char*)buf; size_t total_count = 0; while (total_count < size) { ssize_t count = write(s, data + total_count, size - total_count); if (count == -1) { if (errno != EAGAIN && errno != EINTR) { return 0; } else { continue; } } total_count += count; } return 1; } void get_time(struct timespec* t) { struct timeval tv; #ifdef HAVE_CLOCK_GETTIME /* first try nanosecond precision */ if(clock_gettime(CLOCK_REALTIME, t)>=0) { return; /* success */ } log_msg(LOG_ERR, "clock_gettime: %s", strerror(errno)); #endif /* try millisecond precision */ if(gettimeofday(&tv, NULL)>=0) { t->tv_sec = tv.tv_sec; t->tv_nsec = tv.tv_usec*1000; return; /* success */ } log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); /* whole seconds precision */ t->tv_sec = time(0); t->tv_nsec = 0; } int timespec_compare(const struct timespec *left, const struct timespec *right) { /* Compare seconds. */ if (left->tv_sec < right->tv_sec) { return -1; } else if (left->tv_sec > right->tv_sec) { return 1; } else { /* Seconds are equal, compare nanoseconds. */ if (left->tv_nsec < right->tv_nsec) { return -1; } else if (left->tv_nsec > right->tv_nsec) { return 1; } else { return 0; } } } /* One second is 1e9 nanoseconds. */ #define NANOSECONDS_PER_SECOND 1000000000L void timespec_add(struct timespec *left, const struct timespec *right) { left->tv_sec += right->tv_sec; left->tv_nsec += right->tv_nsec; if (left->tv_nsec >= NANOSECONDS_PER_SECOND) { /* Carry. */ ++left->tv_sec; left->tv_nsec -= NANOSECONDS_PER_SECOND; } } void timespec_subtract(struct timespec *left, const struct timespec *right) { left->tv_sec -= right->tv_sec; left->tv_nsec -= right->tv_nsec; if (left->tv_nsec < 0L) { /* Borrow. */ --left->tv_sec; left->tv_nsec += NANOSECONDS_PER_SECOND; } } uint32_t strtoserial(const char* nptr, const char** endptr) { uint32_t i = 0; uint32_t serial = 0; for(*endptr = nptr; **endptr; (*endptr)++) { switch (**endptr) { case ' ': case '\t': break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if((i*10)/10 != i) /* number too large, return i * with *endptr != 0 as a failure*/ return i; i *= 10; i += (**endptr - '0'); break; default: break; } } serial += i; return serial; } uint32_t strtottl(const char *nptr, const char **endptr) { uint32_t i = 0; uint32_t seconds = 0; for(*endptr = nptr; **endptr; (*endptr)++) { switch (**endptr) { case ' ': case '\t': break; case 's': case 'S': seconds += i; i = 0; break; case 'm': case 'M': seconds += i * 60; i = 0; break; case 'h': case 'H': seconds += i * 60 * 60; i = 0; break; case 'd': case 'D': seconds += i * 60 * 60 * 24; i = 0; break; case 'w': case 'W': seconds += i * 60 * 60 * 24 * 7; i = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i *= 10; i += (**endptr - '0'); break; default: seconds += i; /** * According to RFC2308, Section 8, the MSB * (sign bit) should be set to zero. * If we encounter a value larger than 2^31 -1, * we fall back to the default TTL. */ if ((seconds & MSB_32)) { seconds = DEFAULT_TTL; } return seconds; } } seconds += i; if ((seconds & MSB_32)) { seconds = DEFAULT_TTL; } return seconds; } ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { static char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; size_t i; if (targsize < srclength * 2 + 1) { return -1; } for (i = 0; i < srclength; ++i) { *target++ = hexdigits[src[i] >> 4U]; *target++ = hexdigits[src[i] & 0xfU]; } *target = '\0'; return 2 * srclength; } ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize) { uint8_t *t = target; if(strlen(src) % 2 != 0 || strlen(src)/2 > targsize) { return -1; } while(*src) { if(!isxdigit((unsigned char)src[0]) || !isxdigit((unsigned char)src[1])) return -1; *t++ = hexdigit_to_int(src[0]) * 16 + hexdigit_to_int(src[1]) ; src += 2; } return t-target; } int b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { static char b32[]="0123456789abcdefghijklmnopqrstuv"; char buf[9]; ssize_t len=0; while(srclength > 0) { int t; memset(buf,'\0',sizeof buf); /* xxxxx000 00000000 00000000 00000000 00000000 */ buf[0]=b32[src[0] >> 3]; /* 00000xxx xx000000 00000000 00000000 00000000 */ t=(src[0]&7) << 2; if(srclength > 1) t+=src[1] >> 6; buf[1]=b32[t]; if(srclength == 1) break; /* 00000000 00xxxxx0 00000000 00000000 00000000 */ buf[2]=b32[(src[1] >> 1)&0x1f]; /* 00000000 0000000x xxxx0000 00000000 00000000 */ t=(src[1]&1) << 4; if(srclength > 2) t+=src[2] >> 4; buf[3]=b32[t]; if(srclength == 2) break; /* 00000000 00000000 0000xxxx x0000000 00000000 */ t=(src[2]&0xf) << 1; if(srclength > 3) t+=src[3] >> 7; buf[4]=b32[t]; if(srclength == 3) break; /* 00000000 00000000 00000000 0xxxxx00 00000000 */ buf[5]=b32[(src[3] >> 2)&0x1f]; /* 00000000 00000000 00000000 000000xx xxx00000 */ t=(src[3]&3) << 3; if(srclength > 4) t+=src[4] >> 5; buf[6]=b32[t]; if(srclength == 4) break; /* 00000000 00000000 00000000 00000000 000xxxxx */ buf[7]=b32[src[4]&0x1f]; if(targsize < 8) return -1; src += 5; srclength -= 5; memcpy(target,buf,8); target += 8; targsize -= 8; len += 8; } if(srclength) { if(targsize < strlen(buf)+1) return -1; strlcpy(target, buf, targsize); len += strlen(buf); } else if(targsize < 1) return -1; else *target='\0'; return len; } int b32_pton(const char *src, uint8_t *target, size_t tsize) { char ch; size_t p=0; memset(target,'\0',tsize); while((ch = *src++)) { uint8_t d; size_t b; size_t n; if(p+5 >= tsize*8) return -1; if(isspace((unsigned char)ch)) continue; if(ch >= '0' && ch <= '9') d=ch-'0'; else if(ch >= 'A' && ch <= 'V') d=ch-'A'+10; else if(ch >= 'a' && ch <= 'v') d=ch-'a'+10; else return -1; b=7-p%8; n=p/8; if(b >= 4) target[n]|=d << (b-4); else { target[n]|=d >> (4-b); target[n+1]|=d << (b+4); } p+=5; } return (p+7)/8; } void strip_string(char *str) { char *start = str; char *end = str + strlen(str) - 1; while (isspace((unsigned char)*start)) ++start; if (start > end) { /* Completely blank. */ str[0] = '\0'; } else { while (isspace((unsigned char)*end)) --end; *++end = '\0'; if (str != start) memmove(str, start, end - start + 1); } } int hexdigit_to_int(char ch) { switch (ch) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: abort(); } } /* Number of days per month (except for February in leap years). */ static const int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static int is_leap_year(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } static int leap_days(int y1, int y2) { --y1; --y2; return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); } /* * Code adapted from Python 2.4.1 sources (Lib/calendar.py). */ time_t mktime_from_utc(const struct tm *tm) { int year = 1900 + tm->tm_year; time_t days = 365 * (year - 1970) + leap_days(1970, year); time_t hours; time_t minutes; time_t seconds; int i; for (i = 0; i < tm->tm_mon; ++i) { days += mdays[i]; } if (tm->tm_mon > 1 && is_leap_year(year)) { ++days; } days += tm->tm_mday - 1; hours = days * 24 + tm->tm_hour; minutes = hours * 60 + tm->tm_min; seconds = minutes * 60 + tm->tm_sec; return seconds; } /* code to calculate CRC. Lifted from BSD 4.4 crc.c in cksum(1). BSD license. http://www.tsfr.org/~orc/Code/bsd/bsd-current/cksum/crc.c. or http://gobsd.com/code/freebsd/usr.bin/cksum/crc.c The polynomial is 0x04c11db7L. */ static u_long crctab[] = { 0x0, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] uint32_t compute_crc(uint32_t crc, uint8_t* data, size_t len) { size_t i; for(i=0; i b && a - b > cutoff)) { return -1; } else { return 1; } } uint16_t qid_generate(void) { /* arc4random_uniform not needed because range is a power of 2 */ #ifdef HAVE_ARC4RANDOM return (uint16_t) arc4random(); #else return (uint16_t) random(); #endif } int random_generate(int max) { #ifdef HAVE_ARC4RANDOM_UNIFORM return (int) arc4random_uniform(max); #elif HAVE_ARC4RANDOM return (int) (arc4random() % max); #else return (int) ((unsigned)random() % max); #endif } void cleanup_region(void *data) { region_type *region = (region_type *) data; region_destroy(region); } struct state_pretty_rr* create_pretty_rr(struct region* region) { struct state_pretty_rr* state = (struct state_pretty_rr*) region_alloc(region, sizeof(struct state_pretty_rr)); state->previous_owner_region = region_create(xalloc, free); state->previous_owner = NULL; state->previous_owner_origin = NULL; region_add_cleanup(region, cleanup_region, state->previous_owner_region); return state; } static void set_previous_owner(struct state_pretty_rr *state, const dname_type *dname) { region_free_all(state->previous_owner_region); state->previous_owner = dname_copy(state->previous_owner_region, dname); state->previous_owner_origin = dname_origin( state->previous_owner_region, state->previous_owner); } int print_rr(FILE *out, struct state_pretty_rr *state, rr_type *record, region_type* rr_region, buffer_type* output) { rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(record->type); int result; const dname_type *owner = domain_dname(record->owner); buffer_clear(output); if (state) { if (!state->previous_owner || dname_compare(state->previous_owner, owner) != 0) { const dname_type *owner_origin = dname_origin(rr_region, owner); int origin_changed = (!state->previous_owner_origin || dname_compare(state->previous_owner_origin, owner_origin) != 0); if (origin_changed) { buffer_printf(output, "$ORIGIN %s\n", dname_to_string(owner_origin, NULL)); } set_previous_owner(state, owner); buffer_printf(output, "%s", dname_to_string(owner, state->previous_owner_origin)); region_free_all(rr_region); } } else { buffer_printf(output, "%s", dname_to_string(owner, NULL)); } buffer_printf(output, "\t%lu\t%s\t%s", (unsigned long) record->ttl, rrclass_to_string(record->klass), rrtype_to_string(record->type)); result = print_rdata(output, descriptor, record); if (!result) { /* * Some RDATA failed to print, so print the record's * RDATA in unknown format. */ result = rdata_atoms_to_unknown_string(output, descriptor, record->rdata_count, record->rdatas); } if (result) { buffer_printf(output, "\n"); buffer_flip(output); result = write_data(out, buffer_current(output), buffer_remaining(output)); } return result; } const char* rcode2str(int rc) { switch(rc) { case RCODE_OK: return "NO ERROR"; case RCODE_FORMAT: return "FORMAT ERROR"; case RCODE_SERVFAIL: return "SERVFAIL"; case RCODE_NXDOMAIN: return "NAME ERROR"; case RCODE_IMPL: return "NOT IMPL"; case RCODE_REFUSE: return "REFUSED"; case RCODE_YXDOMAIN: return "YXDOMAIN"; case RCODE_YXRRSET: return "YXRRSET"; case RCODE_NXRRSET: return "NXRRSET"; case RCODE_NOTAUTH: return "SERVER NOT AUTHORITATIVE FOR ZONE"; case RCODE_NOTZONE: /* Name not contained in zone */ return "NOTZONE"; default: return "UNKNOWN ERROR"; } return NULL; /* ENOREACH */ } void addr2str( #ifdef INET6 struct sockaddr_storage *addr #else struct sockaddr_in *addr #endif , char* str, size_t len) { #ifdef INET6 if (addr->ss_family == AF_INET6) { if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, str, len)) strlcpy(str, "[unknown ip6, inet_ntop failed]", len); return; } #endif if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, str, len)) strlcpy(str, "[unknown ip4, inet_ntop failed]", len); } void append_trailing_slash(const char** dirname, region_type* region) { int l = strlen(*dirname); if (l>0 && (*dirname)[l-1] != '/' && l < 0xffffff) { char *dirname_slash = region_alloc(region, l+2); memcpy(dirname_slash, *dirname, l+1); strlcat(dirname_slash, "/", l+2); /* old dirname is leaked, this is only used for chroot, once */ *dirname = dirname_slash; } } int file_inside_chroot(const char* fname, const char* chr) { /* true if filename starts with chroot or is not absolute */ return ((fname && fname[0] && strncmp(fname, chr, strlen(chr)) == 0) || (fname && fname[0] != '/')); } /* * Something went wrong, give error messages and exit. */ void error(const char *format, ...) { va_list args; va_start(args, format); log_vmsg(LOG_ERR, format, args); va_end(args); exit(1); } nsd-4.1.26/region-allocator.h0000664000175000017500000001053412623035675015454 0ustar wouterwouter/* * region-allocator.h -- region based memory allocator. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #ifndef _REGION_ALLOCATOR_H_ #define _REGION_ALLOCATOR_H_ #include typedef struct region region_type; #define DEFAULT_CHUNK_SIZE 4096 #define DEFAULT_LARGE_OBJECT_SIZE (DEFAULT_CHUNK_SIZE / 8) #define DEFAULT_INITIAL_CLEANUP_SIZE 16 /* * mmap allocator constants * */ #ifdef USE_MMAP_ALLOC /* header starts with size_t containing allocated size info and has at least 16 bytes to align the returned memory */ #define MMAP_ALLOC_HEADER_SIZE (sizeof(size_t) >= 16 ? (sizeof(size_t)) : 16) /* mmap allocator uses chunks of 32 4kB pages */ #define MMAP_ALLOC_CHUNK_SIZE ((32 * 4096) - MMAP_ALLOC_HEADER_SIZE) #define MMAP_ALLOC_LARGE_OBJECT_SIZE (MMAP_ALLOC_CHUNK_SIZE / 8) #define MMAP_ALLOC_INITIAL_CLEANUP_SIZE 16 #endif /* USE_MMAP_ALLOC */ /* * Create a new region. */ region_type *region_create(void *(*allocator)(size_t), void (*deallocator)(void *)); /* * Create a new region, with chunk size and large object size. * Note that large_object_size must be <= chunk_size. * Anything larger than the large object size is individually alloced. * large_object_size = chunk_size/8 is reasonable; * initial_cleanup_size is the number of preallocated ptrs for cleanups. * The cleanups are in a growing array, and it must start larger than zero. * If recycle is true, environmentally friendly memory recycling is be enabled. */ region_type *region_create_custom(void *(*allocator)(size_t), void (*deallocator)(void *), size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size, int recycle); /* * Destroy REGION. All memory associated with REGION is freed as if * region_free_all was called. */ void region_destroy(region_type *region); /* * Add a cleanup to REGION. ACTION will be called with DATA as * parameter when the region is freed or destroyed. * * Returns 0 on failure. */ size_t region_add_cleanup(region_type *region, void (*action)(void *), void *data); /* * Remove cleanup, both action and data must match exactly. */ void region_remove_cleanup(region_type *region, void (*action)(void *), void *data); /* * Allocate SIZE bytes of memory inside REGION. The memory is * deallocated when region_free_all is called for this region. */ void *region_alloc(region_type *region, size_t size); /** Allocate array with integer overflow checks, in region */ void *region_alloc_array(region_type *region, size_t num, size_t size); /* * Allocate SIZE bytes of memory inside REGION and copy INIT into it. * The memory is deallocated when region_free_all is called for this * region. */ void *region_alloc_init(region_type *region, const void *init, size_t size); /** * Allocate array (with integer overflow check on sizes), and init with * the given array copied into it. Allocated in the region */ void *region_alloc_array_init(region_type *region, const void *init, size_t num, size_t size); /* * Allocate SIZE bytes of memory inside REGION that are initialized to * 0. The memory is deallocated when region_free_all is called for * this region. */ void *region_alloc_zero(region_type *region, size_t size); /** * Allocate array (with integer overflow check on sizes), and zero it. * Allocated in the region. */ void *region_alloc_array_zero(region_type *region, size_t num, size_t size); /* * Run the cleanup actions and free all memory associated with REGION. */ void region_free_all(region_type *region); /* * Duplicate STRING and allocate the result in REGION. */ char *region_strdup(region_type *region, const char *string); /* * Recycle an allocated memory block. Pass size used to alloc it. * Does nothing if recycling is not enabled for the region. */ void region_recycle(region_type *region, void *block, size_t size); /* * Print some REGION statistics to OUT. */ void region_dump_stats(region_type *region, FILE *out); /* get size of recyclebin */ size_t region_get_recycle_size(region_type* region); /* get size of region memory in use */ size_t region_get_mem(region_type* region); /* get size of region memory unused */ size_t region_get_mem_unused(region_type* region); /* Debug print REGION statistics to LOG. */ void region_log_stats(region_type *region); #endif /* _REGION_ALLOCATOR_H_ */ nsd-4.1.26/nsd-checkconf.8.in0000664000175000017500000000461713401455025015240 0ustar wouterwouter.TH "nsd\-checkconf" "8" "Dec 4, 2018" "NLnet Labs" "nsd 4.1.26" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-checkconf \- NSD configuration file checker. .SH "SYNOPSIS" .B nsd\-checkconf .RB [ \-v ] .RB [ \-f ] .RB [ \-h ] .RB [ \-o .IR option ] .RB [ \-z .IR zonename ] .RB [ \-p .IR pattern ] .RB [ \-s .IR keyname ] .I configfile .SH "DESCRIPTION" .B nsd\-checkconf reads a configuration file. It prints parse errors to standard error, and performs additional checks on the contents. The configfile format is described in nsd.conf(5). .P The utility of this program is to check a config file for errors before using it in nsd(8). This program can also be used for shell scripts to access the nsd config file, using the \-o and \-z options. .P .SH "OPTIONS" .TP .B \-v After reading print the options to standard output in configfile format. Without this option, only success or parse errors are reported. .TP .B \-f Print full pathname when used with files, like with \-o pidfile. This includes the chroot in the way it is applied to the pidfile. .TP .B \-h Print usage help information and exit. .TP .B \-o\fI option Return only this option from the config file. This option can be used in conjunction with the .B \-z and the .B \-p option, or without them to query the server: section. The special value .I zones prints out a list of configured zones. The special value .I patterns prints out a list of configured patterns. .P .RS This option can be used to parse the config file from the shell. If the .B \-z option is given, but the .B \-o option is not given, nothing is printed. .RE .TP .B \-s\fI keyname Prints the key secret (base64 blob) configured for this key in the config file. Used to help shell scripts parse the config file. .TP .B \-p\fI pattern Return the option specified with .B \-o for the given pattern name. .TP .B \-z\fI zonename Return the option specified with .B \-o for zone 'zonename'. .P .RS If this option is not given, the server section of the config file is used. .RE .P .RS The \-o, \-s and \-z option print configfile options to standard output. .RE .SH "FILES" .TP @nsdconfigfile@ default .B NSD configuration file .SH "SEE ALSO" \fInsd\fR(8), \fInsd.conf\fR(5), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. nsd-4.1.26/configlexer.c0000664000175000017500000033563513401455024014514 0ustar wouterwouter#include "configyyrename.h" #line 3 "" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 1 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yynoreturn yy_fatal_error (yyconst char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ (yytext_ptr) -= (yy_more_len); \ yyleng = (int) (yy_cp - (yytext_ptr)); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 109 #define YY_END_OF_BUFFER 110 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[914] = { 0, 1, 1, 97, 97, 101, 101, 105, 105, 110, 108, 1, 95, 96, 2, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 97, 98, 109, 99, 109, 104, 101, 102, 103, 109, 105, 106, 107, 109, 108, 0, 1, 2, 2, 2, 2, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 97, 0, 104, 0, 101, 105, 0, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 67, 108, 108, 108, 108, 108, 108, 66, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 53, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 4, 108, 19, 108, 108, 108, 30, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 42, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 33, 108, 108, 108, 108, 108, 77, 14, 15, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 48, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 55, 108, 3, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 39, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 100, 108, 108, 108, 108, 108, 108, 108, 108, 108, 20, 108, 108, 108, 108, 108, 108, 108, 108, 56, 29, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 25, 108, 108, 108, 108, 108, 18, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 16, 108, 37, 108, 108, 108, 108, 108, 108, 108, 17, 108, 108, 108, 108, 108, 12, 13, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 68, 70, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 34, 108, 108, 38, 43, 108, 108, 35, 108, 54, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 6, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 31, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 22, 108, 108, 108, 41, 108, 108, 108, 44, 108, 108, 108, 108, 108, 108, 108, 9, 108, 108, 108, 108, 108, 108, 108, 108, 5, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 89, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 32, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 8, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 50, 108, 47, 87, 108, 108, 108, 108, 108, 108, 108, 108, 108, 24, 10, 108, 108, 108, 108, 108, 45, 108, 108, 108, 108, 61, 108, 108, 108, 108, 108, 108, 108, 11, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 49, 108, 108, 108, 108, 108, 108, 108, 108, 21, 108, 108, 108, 108, 108, 108, 36, 108, 108, 108, 108, 108, 78, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 69, 108, 74, 108, 108, 108, 108, 108, 108, 108, 108, 108, 59, 108, 108, 108, 108, 108, 108, 108, 83, 108, 7, 27, 28, 86, 108, 92, 108, 93, 108, 108, 108, 108, 58, 108, 108, 108, 108, 108, 46, 108, 108, 108, 108, 108, 108, 108, 108, 82, 108, 108, 108, 108, 57, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 62, 23, 108, 75, 76, 108, 108, 108, 64, 108, 108, 108, 108, 108, 90, 91, 108, 108, 108, 26, 108, 108, 108, 63, 108, 108, 65, 60, 108, 108, 108, 108, 108, 88, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 79, 94, 51, 108, 108, 108, 108, 52, 108, 108, 108, 81, 108, 108, 108, 40, 108, 108, 80, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 71, 72, 108, 108, 108, 73, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 84, 108, 108, 108, 85, 0 } ; static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 8, 1, 9, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 1, 36, 1, 1, 1, 1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst YY_CHAR yy_meta[62] = { 0, 1, 2, 3, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_uint16_t yy_base[923] = { 0, 0, 0, 59, 62, 66, 70, 73, 76, 2334, 2254, 80, 2582, 2582, 83, 63, 79, 119, 71, 110, 77, 81, 117, 121, 64, 155, 157, 161, 101, 149, 129, 85, 159, 209, 2172, 2582, 2582, 2582, 121, 2032, 2065, 2582, 2582, 213, 2028, 2582, 2582, 147, 1990, 217, 87, 0, 221, 0, 0, 203, 196, 151, 204, 112, 216, 213, 205, 194, 220, 222, 232, 257, 236, 226, 215, 250, 254, 255, 247, 259, 253, 256, 270, 271, 273, 296, 264, 292, 304, 244, 305, 294, 300, 314, 310, 320, 326, 1981, 231, 1937, 356, 1966, 1927, 329, 329, 330, 332, 340, 338, 358, 341, 356, 352, 351, 363, 366, 365, 367, 389, 377, 384, 401, 396, 407, 404, 409, 393, 406, 405, 416, 410, 422, 419, 428, 402, 430, 438, 433, 437, 444, 432, 443, 440, 463, 446, 474, 1919, 478, 475, 458, 480, 473, 470, 1866, 483, 481, 500, 501, 499, 509, 507, 515, 494, 512, 520, 525, 523, 526, 516, 531, 518, 550, 1858, 534, 552, 542, 547, 555, 556, 554, 566, 562, 560, 570, 568, 583, 580, 579, 576, 594, 602, 600, 618, 603, 606, 587, 613, 638, 598, 630, 605, 637, 662, 673, 651, 621, 655, 656, 677, 661, 666, 680, 709, 591, 676, 686, 683, 694, 688, 712, 705, 710, 717, 720, 719, 715, 724, 727, 733, 730, 1850, 716, 1819, 738, 744, 746, 1768, 758, 760, 763, 749, 754, 766, 756, 773, 770, 777, 782, 787, 791, 772, 792, 794, 789, 805, 795, 821, 807, 810, 817, 820, 827, 1690, 828, 830, 838, 833, 848, 841, 847, 851, 850, 855, 882, 871, 872, 875, 867, 884, 890, 868, 894, 883, 892, 893, 898, 901, 888, 908, 917, 926, 922, 909, 940, 925, 928, 937, 939, 949, 953, 950, 946, 956, 957, 955, 959, 968, 971, 961, 991, 981, 970, 972, 975, 997, 996, 987, 999, 1000, 1001, 1007, 1010, 1020, 1013, 1023, 1033, 1028, 1022, 1034, 1018, 1687, 1046, 1040, 1037, 1047, 1079, 1656, 1653, 1609, 1036, 1056, 1089, 1066, 1065, 1059, 1075, 1078, 1083, 1085, 1086, 1103, 1094, 1096, 1101, 1104, 1114, 1077, 1116, 1115, 1578, 1128, 1136, 1137, 1141, 1144, 1143, 1151, 1133, 1138, 1157, 1148, 1155, 1158, 1149, 1488, 1177, 1484, 1170, 1176, 1175, 1165, 1172, 1190, 1174, 1192, 1186, 1166, 1196, 1199, 1448, 1212, 1201, 1209, 1210, 1216, 1218, 1213, 1256, 1234, 1237, 1247, 1236, 1244, 1243, 1263, 1267, 1258, 1253, 1273, 1433, 1275, 1260, 1255, 1281, 1295, 1300, 1287, 1290, 1312, 1403, 1306, 1286, 1313, 1291, 1302, 1307, 1322, 1323, 1394, 1390, 1317, 1316, 1321, 1331, 1333, 1344, 1353, 1359, 1347, 1360, 1362, 1363, 1369, 1366, 1355, 1372, 1377, 1351, 1341, 1373, 1388, 1376, 1380, 1343, 1391, 1382, 1407, 1406, 1410, 1397, 1411, 1401, 1417, 1416, 1422, 1427, 1419, 1420, 1337, 1423, 1304, 1438, 1450, 1449, 1444, 1459, 1441, 1454, 1298, 1467, 1469, 1453, 1460, 1476, 1297, 1230, 1475, 1481, 1486, 1472, 1494, 1474, 1499, 1500, 1485, 1489, 1510, 1511, 1497, 1496, 1518, 1506, 1530, 1512, 1525, 1532, 1225, 1219, 1522, 1535, 1534, 1538, 1523, 1545, 1546, 1531, 1549, 1558, 1214, 1573, 1575, 1211, 1184, 1577, 1572, 1183, 1579, 1164, 1580, 1584, 1565, 1585, 1568, 1559, 1597, 1592, 1591, 1602, 1600, 1616, 1611, 1604, 1610, 1606, 1125, 1627, 1629, 1617, 1613, 1626, 1636, 1630, 1639, 1637, 1642, 1648, 1662, 1652, 1659, 1670, 1660, 1649, 1657, 1664, 1123, 1678, 1680, 1683, 1682, 1692, 1686, 1698, 1603, 1713, 1689, 1055, 1716, 1695, 1718, 1050, 1721, 1727, 1717, 1049, 1726, 1709, 1710, 1736, 1741, 1737, 1731, 1039, 1754, 1742, 1759, 1744, 1764, 1757, 1758, 1755, 1038, 1773, 1772, 1770, 1780, 1775, 1785, 1784, 1791, 1798, 1787, 1792, 1788, 1797, 1805, 1808, 931, 1804, 1822, 1825, 1824, 1827, 1817, 1818, 1830, 1835, 1831, 1841, 930, 1845, 1839, 1840, 1844, 1852, 1851, 1867, 1848, 1869, 1876, 1870, 1862, 1877, 1882, 1884, 1878, 1871, 1890, 1893, 1892, 1900, 1896, 929, 1907, 1898, 1903, 1905, 1915, 1909, 1917, 1918, 1925, 1945, 1948, 1947, 1953, 927, 1941, 881, 864, 1951, 1958, 1940, 1942, 1963, 1970, 1966, 1974, 1956, 800, 797, 1967, 1983, 1982, 1972, 1992, 784, 1993, 1989, 1998, 1996, 752, 1997, 2002, 2007, 2006, 2008, 2014, 2022, 751, 2020, 2019, 2036, 2039, 2033, 2034, 2045, 2040, 2046, 2060, 2052, 750, 2057, 2067, 2069, 2075, 2076, 2027, 2090, 2082, 711, 2077, 2072, 2081, 2083, 2093, 2078, 707, 2101, 2104, 2056, 2120, 2114, 704, 2100, 2123, 2127, 2111, 2118, 2129, 2122, 2134, 2136, 2141, 2142, 2140, 2143, 2144, 2145, 2146, 2155, 2159, 2157, 2173, 2151, 2153, 639, 2167, 629, 2169, 2181, 2187, 2177, 2182, 2178, 2192, 2203, 2198, 626, 2208, 2210, 2216, 2195, 2204, 2201, 2224, 625, 2226, 623, 588, 584, 544, 2223, 524, 2227, 491, 2233, 2234, 2243, 2222, 488, 2236, 2249, 2246, 2250, 2256, 456, 2257, 2258, 2261, 2267, 2270, 2269, 2272, 2268, 454, 2262, 2266, 2281, 2280, 448, 2286, 2291, 2283, 2305, 2307, 2302, 2303, 2304, 2294, 2318, 400, 398, 2309, 383, 381, 2316, 2321, 2322, 347, 2306, 2332, 2329, 2336, 2335, 299, 291, 2346, 2341, 2348, 285, 2349, 2352, 2355, 279, 2339, 2356, 245, 231, 2363, 2369, 2365, 2375, 2370, 211, 2371, 2373, 2377, 2380, 2389, 2379, 2402, 2391, 2392, 2385, 2404, 208, 206, 195, 2405, 2413, 2414, 2421, 163, 2401, 2415, 2422, 160, 2417, 2418, 2430, 158, 2435, 2432, 152, 2444, 2446, 2441, 2447, 2439, 2453, 2460, 2455, 2461, 2464, 150, 103, 2475, 2470, 2467, 75, 2471, 2465, 2481, 2479, 2487, 2480, 2497, 2486, 2491, 2510, 2499, 2512, 72, 2513, 2503, 2516, 68, 2582, 2557, 2561, 2565, 90, 2569, 2573, 82, 2575, 2577 } ; static yyconst flex_int16_t yy_def[923] = { 0, 913, 1, 914, 914, 915, 915, 916, 916, 913, 917, 913, 913, 913, 918, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 919, 913, 913, 913, 919, 920, 913, 913, 913, 920, 921, 913, 913, 921, 917, 917, 913, 922, 918, 922, 918, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 919, 919, 920, 920, 913, 921, 921, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 0, 913, 913, 913, 913, 913, 913, 913, 913, 913 } ; static yyconst flex_uint16_t yy_nxt[2644] = { 0, 10, 11, 12, 12, 13, 14, 10, 10, 10, 10, 15, 10, 16, 17, 10, 10, 10, 18, 19, 20, 21, 22, 23, 24, 25, 10, 26, 27, 28, 29, 30, 10, 31, 10, 32, 33, 15, 10, 16, 17, 10, 10, 10, 18, 19, 20, 21, 22, 23, 24, 25, 10, 26, 27, 28, 29, 30, 10, 31, 10, 32, 35, 36, 37, 35, 36, 37, 40, 41, 41, 42, 40, 41, 41, 42, 45, 45, 46, 45, 45, 46, 50, 95, 55, 53, 51, 53, 53, 50, 64, 48, 68, 51, 76, 38, 56, 57, 38, 49, 49, 91, 43, 58, 49, 69, 43, 49, 49, 47, 55, 49, 47, 49, 87, 49, 64, 49, 68, 54, 76, 49, 56, 57, 65, 93, 93, 91, 70, 58, 59, 69, 73, 66, 60, 67, 71, 49, 61, 49, 87, 105, 62, 63, 90, 74, 49, 72, 49, 75, 65, 98, 98, 49, 70, 49, 59, 49, 73, 66, 60, 67, 71, 88, 61, 49, 77, 105, 62, 63, 90, 74, 81, 72, 78, 75, 84, 89, 103, 79, 85, 82, 80, 92, 83, 49, 49, 49, 49, 88, 86, 49, 77, 49, 49, 49, 49, 49, 81, 49, 78, 109, 84, 89, 103, 79, 85, 82, 80, 92, 83, 48, 102, 48, 48, 95, 86, 95, 95, 48, 100, 48, 48, 53, 101, 53, 53, 104, 106, 107, 49, 49, 49, 108, 110, 93, 93, 111, 102, 49, 49, 49, 49, 119, 49, 112, 100, 49, 120, 49, 101, 49, 49, 104, 106, 107, 49, 54, 49, 108, 110, 113, 49, 111, 114, 115, 116, 49, 49, 119, 118, 112, 49, 121, 120, 122, 124, 123, 125, 139, 49, 49, 126, 49, 128, 127, 49, 113, 117, 49, 49, 49, 49, 49, 135, 49, 118, 130, 129, 121, 49, 122, 124, 123, 125, 139, 49, 49, 126, 49, 128, 127, 131, 136, 117, 49, 140, 137, 132, 141, 135, 49, 133, 130, 129, 142, 134, 49, 49, 143, 49, 138, 49, 98, 98, 49, 49, 144, 131, 136, 49, 49, 140, 137, 132, 141, 49, 145, 133, 146, 49, 142, 134, 147, 148, 143, 49, 138, 95, 149, 95, 95, 49, 144, 150, 49, 49, 151, 49, 152, 156, 153, 154, 145, 49, 146, 49, 49, 157, 147, 148, 155, 160, 49, 164, 149, 159, 49, 49, 158, 150, 165, 49, 151, 49, 152, 156, 153, 154, 49, 161, 49, 49, 49, 157, 162, 168, 155, 160, 166, 167, 171, 159, 49, 169, 158, 172, 49, 163, 49, 49, 175, 174, 170, 176, 49, 161, 178, 173, 49, 177, 162, 49, 182, 49, 180, 49, 49, 49, 188, 49, 49, 49, 49, 163, 49, 49, 175, 174, 170, 176, 179, 49, 178, 173, 49, 177, 181, 49, 182, 183, 180, 184, 185, 49, 186, 49, 187, 49, 49, 189, 190, 198, 49, 49, 192, 49, 179, 191, 49, 49, 193, 49, 181, 49, 194, 183, 196, 184, 185, 49, 186, 49, 187, 49, 199, 189, 190, 198, 49, 200, 192, 201, 197, 191, 195, 49, 202, 203, 49, 49, 49, 204, 196, 49, 206, 49, 49, 205, 49, 207, 199, 209, 210, 49, 218, 200, 49, 201, 197, 49, 195, 208, 202, 203, 49, 49, 49, 204, 213, 216, 206, 211, 49, 205, 49, 207, 212, 49, 210, 214, 49, 49, 215, 49, 217, 49, 219, 208, 49, 49, 49, 49, 220, 226, 213, 216, 49, 211, 222, 49, 221, 228, 212, 223, 225, 214, 224, 49, 215, 49, 217, 227, 49, 229, 230, 49, 231, 49, 220, 49, 49, 49, 232, 245, 222, 49, 221, 49, 233, 223, 225, 49, 224, 49, 235, 49, 234, 227, 236, 229, 230, 49, 231, 238, 49, 49, 237, 243, 49, 49, 244, 272, 49, 49, 233, 251, 49, 263, 253, 49, 235, 246, 234, 49, 236, 49, 239, 49, 49, 238, 49, 49, 237, 243, 240, 241, 244, 272, 49, 242, 247, 251, 252, 49, 253, 254, 49, 246, 49, 248, 49, 49, 239, 249, 49, 49, 250, 267, 255, 262, 240, 241, 49, 49, 49, 242, 247, 256, 252, 265, 257, 254, 258, 264, 268, 248, 49, 266, 259, 249, 49, 49, 250, 260, 273, 262, 49, 49, 275, 274, 261, 49, 277, 256, 269, 265, 257, 276, 49, 264, 268, 49, 49, 266, 259, 49, 270, 271, 49, 260, 273, 49, 278, 49, 275, 274, 261, 279, 277, 49, 269, 281, 280, 276, 282, 284, 288, 283, 285, 49, 49, 286, 49, 287, 49, 49, 49, 49, 278, 289, 49, 49, 49, 279, 49, 49, 290, 281, 280, 49, 282, 284, 49, 283, 285, 49, 292, 286, 49, 287, 291, 293, 298, 49, 294, 289, 296, 295, 297, 49, 299, 49, 290, 300, 49, 49, 49, 49, 301, 49, 302, 49, 292, 49, 303, 49, 291, 293, 49, 307, 294, 49, 296, 295, 297, 49, 299, 49, 49, 300, 304, 306, 49, 305, 301, 308, 302, 49, 310, 49, 303, 309, 49, 311, 49, 307, 49, 49, 312, 49, 49, 313, 49, 315, 314, 49, 304, 306, 317, 305, 49, 308, 49, 316, 310, 49, 319, 309, 320, 311, 326, 321, 49, 318, 312, 49, 49, 313, 324, 315, 314, 323, 49, 49, 317, 49, 322, 327, 49, 316, 325, 329, 319, 49, 320, 330, 49, 321, 328, 318, 333, 334, 49, 49, 324, 49, 49, 323, 331, 335, 49, 332, 322, 327, 339, 336, 325, 329, 337, 49, 338, 330, 49, 49, 328, 341, 49, 49, 340, 346, 49, 344, 342, 343, 345, 335, 49, 49, 49, 49, 339, 336, 347, 49, 337, 49, 338, 49, 49, 49, 353, 341, 348, 49, 340, 346, 49, 344, 342, 343, 345, 350, 352, 49, 49, 349, 354, 356, 347, 355, 357, 358, 49, 359, 351, 360, 353, 49, 348, 361, 49, 49, 49, 49, 49, 49, 49, 350, 352, 363, 370, 349, 49, 356, 49, 49, 357, 358, 362, 359, 351, 49, 364, 366, 49, 49, 368, 365, 49, 369, 49, 49, 49, 367, 49, 363, 49, 371, 374, 373, 372, 375, 376, 49, 362, 49, 49, 49, 364, 366, 49, 377, 368, 365, 379, 369, 49, 378, 381, 367, 380, 383, 49, 382, 374, 373, 49, 375, 376, 385, 384, 49, 49, 386, 49, 49, 49, 377, 389, 390, 379, 392, 49, 378, 381, 49, 380, 383, 49, 382, 387, 388, 393, 49, 394, 49, 384, 49, 49, 386, 395, 396, 402, 49, 389, 390, 391, 392, 49, 49, 408, 49, 49, 49, 49, 49, 387, 388, 406, 407, 394, 49, 49, 420, 49, 49, 395, 396, 402, 403, 49, 49, 391, 397, 49, 404, 408, 398, 405, 399, 49, 49, 409, 415, 406, 407, 400, 412, 413, 401, 49, 410, 49, 49, 49, 403, 411, 414, 49, 397, 49, 49, 416, 398, 49, 399, 421, 417, 409, 49, 418, 49, 400, 412, 413, 401, 49, 410, 49, 49, 419, 422, 411, 414, 423, 424, 425, 426, 416, 49, 49, 49, 421, 417, 427, 428, 418, 429, 49, 430, 49, 431, 434, 49, 432, 433, 419, 422, 49, 435, 423, 49, 49, 49, 443, 449, 49, 437, 49, 49, 427, 428, 436, 49, 49, 430, 49, 431, 434, 438, 49, 440, 49, 49, 441, 435, 439, 442, 444, 49, 49, 49, 446, 437, 445, 49, 447, 49, 436, 49, 49, 49, 49, 451, 448, 438, 450, 440, 49, 49, 441, 49, 439, 442, 444, 49, 452, 49, 446, 453, 445, 49, 447, 457, 49, 454, 49, 456, 455, 451, 448, 458, 450, 464, 49, 49, 49, 49, 49, 49, 465, 49, 452, 49, 49, 453, 466, 468, 467, 457, 49, 454, 474, 456, 455, 49, 469, 458, 459, 49, 460, 49, 49, 478, 461, 462, 465, 470, 49, 49, 463, 472, 49, 468, 467, 473, 471, 477, 49, 476, 49, 49, 469, 49, 459, 49, 460, 475, 49, 478, 461, 462, 49, 470, 480, 479, 463, 472, 49, 481, 49, 473, 471, 477, 482, 476, 49, 483, 484, 486, 485, 49, 49, 475, 488, 49, 49, 487, 489, 492, 49, 479, 49, 49, 490, 49, 491, 49, 494, 49, 482, 49, 49, 483, 495, 486, 485, 49, 49, 493, 488, 49, 49, 487, 489, 498, 49, 49, 49, 499, 490, 497, 491, 496, 494, 500, 49, 501, 49, 502, 495, 503, 49, 508, 511, 493, 49, 504, 49, 49, 507, 498, 49, 505, 509, 514, 49, 497, 49, 496, 49, 517, 506, 501, 49, 49, 512, 49, 49, 508, 511, 49, 513, 504, 49, 510, 507, 49, 49, 505, 509, 49, 49, 515, 516, 49, 518, 49, 506, 521, 523, 520, 512, 49, 522, 49, 49, 524, 513, 49, 526, 510, 49, 529, 519, 525, 49, 531, 49, 515, 516, 49, 49, 530, 527, 49, 49, 520, 532, 528, 522, 49, 49, 524, 49, 49, 526, 49, 49, 529, 519, 525, 49, 531, 533, 534, 535, 537, 49, 530, 527, 536, 538, 49, 532, 528, 49, 539, 540, 49, 541, 544, 542, 49, 49, 49, 543, 545, 49, 49, 533, 534, 535, 537, 49, 49, 546, 536, 538, 547, 548, 549, 49, 539, 49, 550, 541, 49, 542, 49, 49, 49, 543, 552, 551, 560, 49, 553, 558, 49, 49, 49, 546, 49, 49, 547, 556, 549, 554, 49, 557, 49, 49, 559, 49, 49, 562, 572, 555, 552, 551, 49, 565, 553, 558, 49, 49, 49, 561, 563, 564, 569, 556, 49, 554, 571, 557, 49, 49, 559, 49, 566, 562, 567, 555, 49, 49, 49, 565, 49, 49, 568, 570, 49, 561, 563, 564, 569, 573, 574, 49, 49, 575, 577, 49, 576, 580, 566, 579, 567, 578, 582, 585, 49, 49, 583, 584, 568, 570, 581, 49, 587, 588, 49, 573, 574, 590, 49, 49, 622, 49, 576, 49, 49, 49, 49, 578, 582, 585, 49, 49, 583, 584, 586, 589, 581, 49, 49, 588, 591, 592, 593, 49, 594, 595, 49, 596, 49, 49, 49, 599, 49, 597, 598, 49, 49, 49, 602, 49, 586, 589, 49, 49, 600, 604, 591, 592, 593, 612, 594, 595, 49, 49, 601, 49, 49, 599, 603, 597, 598, 605, 49, 49, 602, 49, 606, 607, 49, 608, 600, 604, 609, 610, 49, 49, 613, 611, 49, 49, 601, 614, 49, 49, 603, 49, 49, 605, 49, 624, 49, 615, 606, 607, 618, 608, 49, 616, 609, 610, 617, 619, 613, 611, 49, 620, 49, 614, 49, 49, 623, 621, 49, 49, 626, 49, 49, 615, 49, 625, 618, 49, 627, 616, 49, 628, 617, 619, 631, 634, 629, 620, 632, 633, 637, 49, 49, 621, 635, 49, 626, 642, 49, 49, 49, 625, 636, 49, 627, 630, 638, 628, 49, 49, 631, 634, 629, 49, 632, 633, 641, 640, 49, 49, 635, 639, 644, 49, 49, 643, 49, 645, 636, 647, 646, 630, 638, 648, 651, 649, 49, 49, 652, 49, 49, 49, 641, 640, 654, 650, 49, 639, 644, 653, 49, 643, 49, 645, 49, 49, 646, 49, 656, 648, 651, 649, 49, 655, 661, 657, 49, 49, 658, 49, 49, 650, 659, 49, 49, 653, 660, 662, 663, 49, 49, 664, 667, 669, 656, 665, 49, 49, 666, 655, 49, 657, 668, 671, 658, 674, 675, 676, 659, 49, 49, 49, 660, 662, 49, 680, 49, 49, 667, 49, 670, 665, 49, 49, 666, 673, 677, 49, 668, 671, 672, 49, 49, 49, 678, 681, 49, 49, 679, 682, 49, 680, 49, 49, 49, 684, 670, 683, 686, 685, 49, 673, 677, 688, 49, 687, 672, 689, 49, 49, 678, 49, 49, 49, 679, 690, 694, 695, 49, 49, 49, 684, 693, 683, 49, 685, 49, 691, 692, 688, 699, 687, 49, 689, 49, 49, 696, 701, 49, 697, 49, 690, 49, 695, 698, 49, 703, 49, 693, 49, 700, 49, 702, 691, 692, 704, 699, 49, 705, 49, 49, 49, 696, 701, 706, 697, 708, 49, 707, 99, 698, 709, 703, 710, 97, 712, 700, 713, 702, 96, 711, 704, 49, 49, 49, 714, 715, 49, 722, 49, 49, 716, 718, 49, 707, 49, 717, 709, 49, 710, 49, 712, 719, 713, 720, 49, 711, 721, 49, 49, 725, 714, 49, 728, 49, 724, 49, 716, 718, 723, 726, 727, 717, 94, 49, 49, 731, 733, 719, 732, 720, 49, 49, 721, 49, 49, 725, 729, 49, 49, 49, 724, 730, 751, 49, 723, 726, 727, 49, 49, 49, 734, 731, 735, 736, 732, 49, 737, 739, 740, 738, 49, 49, 729, 49, 742, 741, 743, 730, 49, 99, 745, 763, 97, 96, 49, 49, 734, 49, 735, 736, 49, 49, 737, 739, 740, 738, 49, 49, 744, 746, 742, 741, 743, 49, 747, 748, 745, 49, 49, 749, 750, 49, 752, 755, 756, 753, 754, 758, 49, 757, 49, 759, 760, 49, 744, 746, 49, 49, 49, 49, 747, 748, 49, 49, 49, 749, 750, 761, 762, 755, 756, 49, 754, 758, 49, 757, 764, 759, 760, 766, 765, 49, 49, 769, 771, 49, 767, 768, 770, 773, 772, 774, 49, 761, 762, 49, 775, 776, 778, 49, 780, 49, 764, 49, 49, 766, 765, 777, 49, 769, 49, 779, 767, 768, 770, 49, 772, 49, 782, 781, 783, 49, 49, 49, 49, 49, 49, 49, 785, 786, 784, 787, 49, 777, 49, 789, 49, 779, 49, 788, 49, 790, 791, 794, 782, 781, 783, 801, 49, 793, 49, 792, 795, 94, 49, 786, 784, 787, 49, 49, 796, 789, 49, 49, 797, 788, 798, 790, 49, 794, 799, 800, 802, 49, 803, 793, 49, 792, 795, 49, 804, 805, 49, 806, 49, 49, 796, 807, 812, 49, 797, 49, 798, 808, 809, 811, 799, 49, 802, 810, 803, 813, 814, 49, 49, 49, 804, 49, 49, 806, 815, 816, 817, 807, 49, 49, 819, 49, 818, 808, 809, 811, 820, 824, 49, 810, 821, 49, 814, 822, 49, 49, 823, 825, 826, 49, 815, 49, 49, 49, 827, 830, 49, 49, 818, 828, 831, 49, 49, 49, 49, 49, 821, 49, 829, 822, 832, 835, 823, 825, 826, 49, 49, 833, 49, 834, 827, 49, 838, 836, 837, 828, 49, 839, 841, 49, 842, 843, 840, 913, 829, 844, 832, 49, 49, 49, 49, 49, 49, 833, 49, 834, 845, 846, 838, 836, 837, 49, 848, 49, 841, 849, 49, 49, 840, 847, 850, 844, 851, 852, 49, 913, 853, 49, 855, 854, 49, 49, 845, 846, 49, 856, 49, 857, 848, 861, 862, 49, 863, 49, 49, 847, 850, 49, 851, 852, 49, 49, 853, 859, 855, 854, 858, 860, 49, 864, 49, 856, 865, 857, 49, 49, 49, 867, 49, 866, 49, 868, 49, 872, 49, 49, 870, 869, 871, 859, 49, 873, 858, 860, 49, 864, 49, 49, 865, 874, 876, 879, 875, 867, 877, 866, 49, 49, 878, 49, 49, 883, 870, 869, 871, 880, 881, 873, 49, 49, 49, 882, 49, 49, 884, 874, 49, 49, 875, 887, 877, 885, 890, 886, 878, 49, 889, 49, 888, 891, 49, 880, 881, 897, 49, 893, 49, 882, 894, 49, 884, 49, 49, 892, 895, 887, 899, 885, 49, 886, 49, 900, 889, 901, 888, 49, 49, 896, 898, 49, 49, 893, 49, 902, 894, 49, 49, 903, 908, 892, 49, 904, 899, 905, 49, 49, 49, 900, 906, 901, 907, 49, 49, 896, 898, 912, 49, 910, 909, 902, 911, 913, 49, 903, 49, 913, 913, 904, 49, 905, 913, 913, 913, 913, 906, 49, 907, 49, 49, 913, 913, 49, 913, 910, 909, 913, 911, 34, 34, 34, 34, 39, 39, 39, 39, 44, 44, 44, 44, 52, 52, 913, 52, 93, 93, 98, 98, 53, 53, 913, 53, 9, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913 } ; static yyconst flex_int16_t yy_chk[2644] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 11, 920, 15, 14, 11, 14, 14, 50, 18, 917, 20, 50, 24, 3, 15, 16, 4, 15, 24, 31, 5, 16, 912, 21, 6, 18, 908, 7, 15, 895, 8, 20, 28, 16, 18, 21, 20, 14, 24, 31, 15, 16, 19, 38, 38, 31, 22, 16, 17, 21, 23, 19, 17, 19, 22, 28, 17, 891, 28, 59, 17, 17, 30, 23, 19, 22, 59, 23, 19, 47, 47, 22, 22, 17, 17, 23, 23, 19, 17, 19, 22, 29, 17, 30, 25, 59, 17, 17, 30, 23, 26, 22, 25, 23, 27, 29, 57, 25, 27, 26, 25, 32, 26, 29, 890, 57, 879, 29, 27, 25, 25, 26, 876, 32, 872, 27, 26, 868, 25, 63, 27, 29, 57, 25, 27, 26, 25, 32, 26, 33, 56, 33, 33, 43, 27, 43, 43, 49, 55, 49, 49, 52, 55, 52, 52, 58, 60, 61, 63, 863, 56, 62, 64, 94, 94, 65, 56, 55, 58, 62, 862, 69, 861, 66, 55, 849, 70, 61, 55, 70, 60, 58, 60, 61, 64, 52, 65, 62, 64, 66, 69, 65, 67, 67, 67, 843, 66, 69, 68, 66, 68, 71, 70, 72, 74, 73, 75, 85, 85, 842, 76, 74, 78, 77, 71, 66, 67, 76, 72, 73, 77, 67, 82, 75, 68, 80, 79, 71, 82, 72, 74, 73, 75, 85, 78, 79, 76, 80, 78, 77, 81, 83, 67, 839, 86, 84, 81, 87, 82, 835, 81, 80, 79, 88, 81, 831, 83, 89, 87, 84, 81, 99, 99, 830, 88, 90, 81, 83, 84, 86, 86, 84, 81, 87, 90, 91, 81, 92, 89, 88, 81, 100, 101, 89, 91, 84, 96, 102, 96, 96, 92, 90, 103, 100, 101, 104, 102, 105, 109, 106, 107, 91, 104, 92, 103, 106, 110, 100, 101, 108, 113, 824, 115, 102, 112, 109, 108, 111, 103, 116, 107, 104, 105, 105, 109, 106, 107, 110, 114, 112, 111, 113, 110, 114, 118, 108, 113, 117, 117, 120, 112, 115, 119, 111, 121, 820, 114, 819, 116, 123, 122, 119, 124, 114, 114, 126, 121, 122, 125, 114, 118, 130, 817, 128, 816, 117, 130, 136, 120, 124, 123, 119, 114, 121, 126, 123, 122, 119, 124, 127, 125, 126, 121, 128, 125, 129, 127, 130, 131, 128, 132, 133, 129, 134, 131, 135, 136, 133, 137, 138, 145, 134, 132, 140, 138, 127, 139, 137, 135, 141, 140, 129, 805, 143, 131, 144, 132, 133, 800, 134, 791, 135, 145, 146, 137, 138, 145, 139, 147, 140, 148, 144, 139, 143, 148, 150, 151, 147, 141, 144, 152, 144, 143, 154, 146, 151, 153, 150, 155, 146, 157, 158, 785, 166, 147, 780, 148, 144, 158, 143, 156, 150, 151, 154, 152, 153, 152, 161, 164, 154, 159, 156, 153, 155, 155, 160, 159, 158, 162, 157, 164, 163, 166, 165, 160, 167, 156, 162, 778, 161, 163, 169, 175, 161, 164, 165, 159, 171, 169, 170, 177, 160, 172, 174, 162, 173, 171, 163, 776, 165, 176, 172, 178, 179, 167, 180, 170, 169, 175, 173, 174, 181, 191, 171, 178, 170, 177, 182, 172, 174, 176, 173, 180, 184, 179, 183, 176, 185, 178, 179, 184, 180, 187, 183, 182, 186, 189, 181, 775, 190, 209, 191, 774, 182, 194, 209, 201, 196, 185, 184, 192, 183, 194, 185, 187, 188, 186, 189, 187, 196, 190, 186, 189, 188, 188, 190, 209, 192, 188, 193, 194, 195, 188, 196, 197, 201, 192, 773, 193, 771, 763, 188, 193, 753, 195, 193, 205, 198, 200, 188, 188, 197, 193, 751, 188, 193, 198, 195, 203, 198, 197, 199, 202, 206, 193, 200, 204, 199, 193, 202, 203, 193, 199, 210, 200, 205, 198, 212, 211, 199, 206, 214, 198, 207, 203, 198, 213, 199, 202, 206, 210, 204, 204, 199, 207, 208, 208, 212, 199, 210, 211, 215, 214, 212, 211, 199, 216, 214, 213, 207, 218, 217, 213, 219, 221, 225, 220, 222, 728, 216, 223, 722, 224, 208, 217, 715, 215, 215, 227, 221, 227, 218, 216, 220, 219, 229, 218, 217, 222, 219, 221, 223, 220, 222, 225, 231, 223, 224, 224, 230, 233, 238, 229, 234, 227, 236, 235, 237, 230, 239, 231, 229, 240, 236, 706, 694, 686, 241, 237, 241, 239, 231, 233, 242, 234, 230, 233, 235, 246, 234, 238, 236, 235, 237, 241, 239, 246, 240, 240, 243, 245, 242, 244, 241, 247, 241, 243, 249, 681, 242, 248, 244, 250, 249, 246, 245, 247, 251, 248, 251, 252, 675, 254, 253, 674, 243, 245, 256, 244, 250, 247, 253, 255, 249, 254, 259, 248, 260, 250, 264, 261, 255, 257, 251, 256, 252, 252, 263, 254, 253, 262, 257, 259, 256, 260, 261, 265, 262, 255, 263, 267, 259, 261, 260, 268, 264, 261, 266, 257, 270, 271, 265, 263, 263, 267, 266, 262, 269, 272, 268, 269, 261, 265, 276, 273, 263, 267, 274, 664, 275, 268, 273, 276, 266, 278, 270, 271, 277, 283, 272, 281, 279, 280, 282, 272, 663, 269, 278, 274, 276, 273, 284, 283, 274, 275, 275, 279, 280, 277, 288, 278, 285, 281, 277, 283, 282, 281, 279, 280, 282, 286, 287, 284, 288, 285, 289, 290, 284, 289, 291, 292, 285, 293, 286, 294, 288, 287, 285, 295, 290, 286, 661, 291, 647, 624, 612, 286, 287, 297, 304, 285, 292, 290, 293, 289, 291, 292, 296, 293, 286, 297, 298, 300, 294, 296, 302, 299, 295, 303, 300, 298, 299, 301, 301, 297, 304, 305, 307, 306, 305, 308, 309, 302, 296, 307, 303, 308, 298, 300, 309, 310, 302, 299, 312, 303, 306, 311, 314, 301, 313, 316, 312, 315, 307, 306, 305, 308, 309, 318, 317, 311, 310, 319, 313, 314, 315, 310, 322, 323, 312, 325, 316, 311, 314, 317, 313, 316, 319, 315, 320, 321, 327, 325, 328, 318, 317, 323, 320, 319, 329, 330, 335, 322, 322, 323, 324, 325, 321, 324, 340, 335, 329, 596, 587, 328, 320, 321, 338, 339, 328, 327, 330, 352, 579, 575, 329, 330, 335, 336, 571, 336, 324, 331, 340, 337, 340, 331, 337, 331, 339, 338, 341, 347, 338, 339, 331, 344, 345, 331, 341, 342, 352, 342, 331, 336, 343, 346, 343, 331, 344, 345, 348, 331, 337, 331, 353, 349, 341, 347, 350, 348, 331, 344, 345, 331, 349, 342, 346, 350, 351, 354, 343, 346, 356, 357, 358, 359, 348, 351, 354, 353, 353, 349, 360, 361, 350, 362, 560, 363, 540, 364, 366, 356, 365, 365, 351, 354, 363, 367, 356, 357, 358, 364, 376, 382, 359, 369, 361, 360, 360, 361, 368, 366, 369, 363, 362, 364, 366, 371, 367, 373, 365, 368, 374, 367, 371, 375, 377, 523, 376, 382, 379, 369, 378, 373, 380, 377, 368, 379, 375, 374, 371, 384, 381, 371, 383, 373, 521, 518, 374, 381, 371, 375, 377, 378, 386, 380, 379, 387, 378, 383, 380, 391, 384, 388, 387, 390, 389, 384, 381, 392, 383, 394, 388, 389, 517, 386, 392, 514, 395, 390, 386, 391, 503, 387, 396, 398, 397, 391, 502, 388, 403, 390, 389, 481, 399, 392, 393, 394, 393, 397, 395, 408, 393, 393, 395, 400, 399, 398, 393, 401, 396, 398, 397, 402, 400, 407, 403, 406, 408, 393, 399, 402, 393, 407, 393, 404, 400, 408, 393, 393, 401, 400, 410, 409, 393, 401, 404, 411, 406, 402, 400, 407, 412, 406, 409, 413, 414, 417, 416, 417, 412, 404, 419, 413, 419, 418, 420, 423, 410, 409, 480, 474, 421, 411, 422, 420, 427, 466, 412, 416, 421, 413, 428, 417, 416, 414, 418, 426, 419, 427, 426, 418, 420, 431, 428, 422, 423, 432, 421, 430, 422, 429, 427, 433, 429, 434, 430, 435, 428, 436, 464, 440, 444, 426, 444, 437, 449, 431, 439, 431, 434, 438, 441, 447, 443, 430, 432, 429, 440, 451, 438, 434, 433, 435, 445, 436, 437, 440, 444, 439, 446, 437, 438, 442, 439, 441, 445, 438, 441, 447, 442, 448, 450, 448, 452, 451, 438, 454, 456, 453, 445, 446, 455, 425, 450, 457, 446, 424, 459, 442, 455, 462, 452, 458, 457, 465, 415, 448, 450, 453, 452, 463, 460, 454, 456, 453, 467, 461, 455, 459, 458, 457, 462, 463, 459, 460, 465, 462, 452, 458, 461, 465, 468, 469, 470, 472, 405, 463, 460, 471, 473, 467, 467, 461, 472, 475, 476, 470, 477, 482, 478, 385, 469, 468, 479, 483, 477, 473, 468, 469, 470, 472, 471, 478, 484, 471, 473, 485, 486, 487, 475, 475, 476, 488, 477, 485, 478, 487, 482, 479, 479, 490, 489, 497, 483, 491, 495, 372, 490, 484, 484, 370, 491, 485, 493, 487, 492, 486, 494, 495, 494, 496, 488, 489, 499, 511, 492, 490, 489, 497, 504, 491, 495, 492, 493, 499, 498, 500, 501, 508, 493, 496, 492, 510, 494, 504, 508, 496, 500, 505, 499, 506, 492, 498, 511, 501, 504, 506, 505, 507, 509, 507, 498, 500, 501, 508, 512, 513, 509, 510, 515, 519, 512, 516, 524, 505, 522, 506, 520, 526, 529, 513, 529, 527, 528, 507, 509, 525, 526, 531, 532, 528, 512, 513, 534, 520, 515, 568, 516, 516, 519, 355, 522, 524, 520, 526, 529, 525, 527, 527, 528, 530, 533, 525, 532, 531, 532, 535, 536, 537, 530, 538, 539, 534, 541, 533, 568, 537, 544, 539, 542, 543, 334, 538, 536, 547, 544, 530, 533, 535, 543, 545, 549, 535, 536, 537, 557, 538, 539, 545, 541, 546, 542, 547, 544, 548, 542, 543, 550, 546, 549, 547, 548, 551, 552, 550, 553, 545, 549, 554, 555, 551, 557, 558, 556, 553, 333, 546, 559, 332, 558, 548, 554, 556, 550, 552, 570, 559, 561, 551, 552, 564, 553, 555, 562, 554, 555, 563, 565, 558, 556, 561, 566, 562, 559, 564, 563, 569, 567, 566, 326, 573, 570, 258, 561, 565, 572, 564, 573, 574, 562, 567, 576, 563, 565, 578, 582, 577, 566, 580, 581, 585, 581, 582, 567, 583, 569, 573, 591, 572, 578, 574, 572, 584, 576, 574, 577, 586, 576, 580, 577, 578, 582, 577, 586, 580, 581, 590, 589, 583, 585, 583, 588, 593, 584, 589, 592, 591, 594, 584, 597, 595, 577, 586, 598, 601, 599, 588, 595, 602, 593, 594, 590, 590, 589, 604, 600, 592, 588, 593, 603, 232, 592, 599, 594, 598, 597, 595, 601, 606, 598, 601, 599, 600, 605, 611, 607, 603, 602, 608, 606, 608, 600, 609, 604, 607, 603, 610, 613, 614, 609, 605, 615, 618, 620, 606, 616, 613, 610, 617, 605, 611, 607, 619, 622, 608, 626, 627, 628, 609, 618, 619, 228, 610, 613, 614, 632, 616, 615, 618, 617, 621, 616, 620, 622, 617, 625, 629, 621, 619, 622, 623, 626, 627, 623, 630, 633, 628, 625, 631, 634, 632, 632, 226, 630, 629, 636, 621, 635, 638, 637, 168, 625, 629, 640, 636, 639, 623, 641, 149, 631, 630, 633, 635, 641, 631, 642, 645, 646, 634, 637, 640, 636, 644, 635, 638, 637, 639, 642, 643, 640, 651, 639, 642, 641, 644, 643, 648, 653, 646, 649, 649, 642, 645, 646, 650, 650, 655, 651, 644, 648, 652, 653, 654, 642, 643, 656, 651, 652, 657, 654, 655, 142, 648, 653, 658, 649, 660, 656, 659, 98, 650, 662, 655, 665, 97, 667, 652, 668, 654, 95, 666, 656, 667, 662, 668, 669, 670, 657, 679, 659, 658, 671, 673, 665, 659, 660, 672, 662, 673, 665, 666, 667, 676, 668, 677, 669, 666, 678, 671, 676, 683, 669, 670, 687, 679, 682, 672, 671, 673, 680, 684, 685, 672, 93, 678, 677, 690, 692, 676, 691, 677, 683, 48, 678, 680, 682, 683, 688, 685, 687, 684, 682, 689, 712, 688, 680, 684, 685, 690, 689, 691, 693, 690, 695, 696, 691, 692, 697, 699, 700, 698, 696, 695, 688, 693, 702, 701, 703, 689, 712, 44, 705, 725, 40, 39, 699, 700, 693, 697, 695, 696, 698, 702, 697, 699, 700, 698, 701, 703, 704, 707, 702, 701, 703, 705, 708, 709, 705, 725, 707, 710, 711, 704, 713, 716, 717, 713, 714, 719, 708, 718, 709, 720, 721, 717, 704, 707, 710, 711, 716, 721, 708, 709, 718, 714, 719, 710, 711, 723, 724, 716, 717, 713, 714, 719, 720, 718, 726, 720, 721, 729, 727, 729, 723, 732, 734, 724, 730, 731, 733, 736, 735, 737, 732, 723, 724, 727, 738, 739, 741, 733, 743, 726, 726, 735, 730, 729, 727, 740, 731, 732, 734, 742, 730, 731, 733, 736, 735, 737, 745, 744, 746, 740, 738, 739, 741, 742, 743, 744, 748, 749, 747, 750, 749, 740, 750, 754, 745, 742, 747, 752, 746, 755, 756, 759, 745, 744, 746, 767, 752, 758, 754, 757, 760, 34, 748, 749, 747, 750, 757, 759, 761, 754, 755, 758, 762, 752, 764, 755, 756, 759, 765, 766, 768, 760, 769, 758, 767, 757, 760, 762, 770, 772, 769, 777, 761, 768, 761, 779, 786, 764, 762, 765, 764, 781, 782, 784, 765, 766, 768, 783, 769, 787, 788, 784, 777, 770, 770, 772, 779, 777, 789, 790, 792, 779, 781, 782, 794, 786, 793, 781, 782, 784, 795, 799, 783, 783, 796, 788, 788, 797, 787, 789, 798, 801, 801, 10, 789, 790, 792, 793, 802, 806, 794, 801, 793, 803, 807, 802, 795, 799, 797, 796, 796, 798, 804, 797, 808, 811, 798, 801, 801, 804, 803, 809, 808, 810, 802, 806, 814, 812, 813, 803, 807, 815, 821, 814, 822, 823, 818, 9, 804, 825, 808, 811, 812, 813, 809, 825, 810, 809, 818, 810, 826, 827, 814, 812, 813, 821, 829, 815, 821, 832, 822, 823, 818, 828, 833, 825, 834, 836, 827, 0, 837, 826, 840, 838, 829, 828, 826, 827, 840, 841, 833, 844, 829, 848, 850, 832, 851, 834, 836, 828, 833, 837, 834, 836, 838, 841, 837, 846, 840, 838, 845, 847, 844, 852, 846, 841, 853, 844, 845, 848, 850, 855, 851, 854, 847, 856, 852, 860, 855, 853, 858, 857, 859, 846, 859, 864, 845, 847, 854, 852, 857, 858, 853, 865, 867, 871, 866, 855, 869, 854, 869, 856, 870, 860, 864, 877, 858, 857, 859, 873, 874, 864, 865, 866, 870, 875, 873, 874, 878, 865, 867, 871, 866, 882, 869, 880, 885, 881, 870, 875, 884, 878, 883, 886, 877, 873, 874, 894, 884, 888, 882, 875, 889, 880, 878, 881, 883, 887, 892, 882, 897, 880, 885, 881, 887, 898, 884, 899, 883, 886, 888, 893, 896, 889, 897, 888, 894, 900, 889, 893, 896, 901, 906, 887, 892, 902, 897, 903, 899, 901, 898, 898, 904, 899, 905, 903, 900, 893, 896, 911, 904, 909, 907, 900, 910, 0, 902, 901, 906, 0, 0, 902, 910, 903, 0, 0, 0, 0, 904, 905, 905, 907, 909, 0, 0, 911, 0, 909, 907, 0, 910, 914, 914, 914, 914, 915, 915, 915, 915, 916, 916, 916, 916, 918, 918, 0, 918, 919, 919, 921, 921, 922, 922, 0, 922, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected static int yy_more_flag = 0; static int yy_more_len = 0; #define yymore() ((yy_more_flag) = 1) #define YY_MORE_ADJ (yy_more_len) #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "configlexer.lex" #line 2 "configlexer.lex" /* * configlexer.lex - lexical analyzer for NSD config file * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved * * See LICENSE for the license. * */ /* because flex keeps having sign-unsigned compare problems that are unfixed*/ #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) #pragma GCC diagnostic ignored "-Wsign-compare" #endif #include "config.h" #include #include #include #include #ifdef HAVE_GLOB_H # include #endif #include "options.h" #include "configyyrename.h" #include "configparser.h" void c_error(const char *message); #if 0 #define LEXOUT(s) printf s /* used ONLY when debugging */ #else #define LEXOUT(s) #endif struct inc_state { char* filename; int line; YY_BUFFER_STATE buffer; struct inc_state* next; }; static struct inc_state* config_include_stack = NULL; static int inc_depth = 0; static int inc_prev = 0; static int num_args = 0; void init_cfg_parse(void) { config_include_stack = NULL; inc_depth = 0; inc_prev = 0; num_args = 0; } static void config_start_include(const char* filename) { FILE *input; struct inc_state* s; char* nm; if(inc_depth++ > 10000000) { c_error_msg("too many include files"); return; } if(strlen(filename) == 0) { c_error_msg("empty include file name"); return; } s = (struct inc_state*)malloc(sizeof(*s)); if(!s) { c_error_msg("include %s: malloc failure", filename); return; } nm = strdup(filename); if(!nm) { c_error_msg("include %s: strdup failure", filename); free(s); return; } input = fopen(filename, "r"); if(!input) { c_error_msg("cannot open include file '%s': %s", filename, strerror(errno)); free(s); free(nm); return; } LEXOUT(("switch_to_include_file(%s) ", filename)); s->filename = cfg_parser->filename; s->line = cfg_parser->line; s->buffer = YY_CURRENT_BUFFER; s->next = config_include_stack; config_include_stack = s; cfg_parser->filename = nm; cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input,YY_BUF_SIZE)); } static void config_start_include_glob(const char* filename) { /* check for wildcards */ #ifdef HAVE_GLOB glob_t g; size_t i; int r, flags; #endif /* HAVE_GLOB */ if (cfg_parser->chroot) { int l = strlen(cfg_parser->chroot); /* chroot has trailing slash */ if (strncmp(cfg_parser->chroot, filename, l) != 0) { c_error_msg("include file '%s' is not relative to chroot '%s'", filename, cfg_parser->chroot); return; } filename += l - 1; /* strip chroot without trailing slash */ } #ifdef HAVE_GLOB if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') && !strchr(filename, '{') && !strchr(filename, '~'))) { flags = 0 #ifdef GLOB_ERR | GLOB_ERR #endif /* do not set GLOB_NOSORT so the results are sorted and in a predictable order. */ #ifdef GLOB_BRACE | GLOB_BRACE #endif #ifdef GLOB_TILDE | GLOB_TILDE #endif ; memset(&g, 0, sizeof(g)); r = glob(filename, flags, NULL, &g); if(r) { /* some error */ globfree(&g); if(r == GLOB_NOMATCH) return; /* no matches for pattern */ config_start_include(filename); /* let original deal with it */ return; } /* process files found, if any */ for(i=0; i<(size_t)g.gl_pathc; i++) { config_start_include(g.gl_pathv[i]); } globfree(&g); return; } #endif /* HAVE_GLOB */ config_start_include(filename); } static void config_end_include(void) { struct inc_state* s = config_include_stack; --inc_depth; if(!s) return; free(cfg_parser->filename); cfg_parser->filename = s->filename; cfg_parser->line = s->line; yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(s->buffer); config_include_stack = s->next; free(s); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer(yyin,YY_BUF_SIZE ); \ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \ } #endif #define YY_NO_INPUT 1 #line 181 "configlexer.lex" #ifndef YY_NO_UNPUT #define YY_NO_UNPUT 1 #endif #ifndef YY_NO_INPUT #define YY_NO_INPUT 1 #endif #line 1526 "" #define INITIAL 0 #define quotedstring 1 #define include 2 #define include_quoted 3 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (void ); int yyget_debug (void ); void yyset_debug (int debug_flag ); YY_EXTRA_TYPE yyget_extra (void ); void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); void yyset_in (FILE * _in_str ); FILE *yyget_out (void ); void yyset_out (FILE * _out_str ); int yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); void yyset_lineno (int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } { #line 199 "configlexer.lex" #line 1747 "" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { (yy_more_len) = 0; if ( (yy_more_flag) ) { (yy_more_len) = (yy_c_buf_p) - (yytext_ptr); (yy_more_flag) = 0; } yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 914 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 2582 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 200 "configlexer.lex" { LEXOUT(("SP ")); /* ignore */ } YY_BREAK case 2: YY_RULE_SETUP #line 201 "configlexer.lex" { LEXOUT(("comment(%s) ", yytext)); /* ignore */ } YY_BREAK case 3: YY_RULE_SETUP #line 202 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;} YY_BREAK case 4: YY_RULE_SETUP #line 203 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;} YY_BREAK case 5: YY_RULE_SETUP #line 204 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} YY_BREAK case 6: YY_RULE_SETUP #line 205 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;} YY_BREAK case 7: YY_RULE_SETUP #line 206 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;} YY_BREAK case 8: YY_RULE_SETUP #line 207 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;} YY_BREAK case 9: YY_RULE_SETUP #line 208 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;} YY_BREAK case 10: YY_RULE_SETUP #line 209 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;} YY_BREAK case 11: YY_RULE_SETUP #line 210 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;} YY_BREAK case 12: YY_RULE_SETUP #line 211 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;} YY_BREAK case 13: YY_RULE_SETUP #line 212 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;} YY_BREAK case 14: YY_RULE_SETUP #line 213 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;} YY_BREAK case 15: YY_RULE_SETUP #line 214 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;} YY_BREAK case 16: YY_RULE_SETUP #line 215 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;} YY_BREAK case 17: YY_RULE_SETUP #line 216 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;} YY_BREAK case 18: YY_RULE_SETUP #line 217 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;} YY_BREAK case 19: YY_RULE_SETUP #line 218 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NSID;} YY_BREAK case 20: YY_RULE_SETUP #line 219 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;} YY_BREAK case 21: YY_RULE_SETUP #line 220 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;} YY_BREAK case 22: YY_RULE_SETUP #line 221 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;} YY_BREAK case 23: YY_RULE_SETUP #line 222 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;} YY_BREAK case 24: YY_RULE_SETUP #line 223 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;} YY_BREAK case 25: YY_RULE_SETUP #line 224 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;} YY_BREAK case 26: YY_RULE_SETUP #line 225 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;} YY_BREAK case 27: YY_RULE_SETUP #line 226 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;} YY_BREAK case 28: YY_RULE_SETUP #line 227 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;} YY_BREAK case 29: YY_RULE_SETUP #line 228 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;} YY_BREAK case 30: YY_RULE_SETUP #line 229 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;} YY_BREAK case 31: YY_RULE_SETUP #line 230 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;} YY_BREAK case 32: YY_RULE_SETUP #line 231 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;} YY_BREAK case 33: YY_RULE_SETUP #line 232 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;} YY_BREAK case 34: YY_RULE_SETUP #line 233 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;} YY_BREAK case 35: YY_RULE_SETUP #line 234 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;} YY_BREAK case 36: YY_RULE_SETUP #line 235 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;} YY_BREAK case 37: YY_RULE_SETUP #line 236 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;} YY_BREAK case 38: YY_RULE_SETUP #line 237 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;} YY_BREAK case 39: YY_RULE_SETUP #line 238 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;} YY_BREAK case 40: YY_RULE_SETUP #line 239 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;} YY_BREAK case 41: YY_RULE_SETUP #line 240 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;} YY_BREAK case 42: YY_RULE_SETUP #line 241 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;} YY_BREAK case 43: YY_RULE_SETUP #line 242 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;} YY_BREAK case 44: YY_RULE_SETUP #line 243 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;} YY_BREAK case 45: YY_RULE_SETUP #line 244 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;} YY_BREAK case 46: YY_RULE_SETUP #line 245 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;} YY_BREAK case 47: YY_RULE_SETUP #line 246 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;} YY_BREAK case 48: YY_RULE_SETUP #line 247 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;} YY_BREAK case 49: YY_RULE_SETUP #line 248 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;} YY_BREAK case 50: YY_RULE_SETUP #line 249 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;} YY_BREAK case 51: YY_RULE_SETUP #line 250 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;} YY_BREAK case 52: YY_RULE_SETUP #line 251 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;} YY_BREAK case 53: YY_RULE_SETUP #line 252 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_KEY;} YY_BREAK case 54: YY_RULE_SETUP #line 253 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;} YY_BREAK case 55: YY_RULE_SETUP #line 254 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;} YY_BREAK case 56: YY_RULE_SETUP #line 255 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;} YY_BREAK case 57: YY_RULE_SETUP #line 256 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDEPATTERN;} YY_BREAK case 58: YY_RULE_SETUP #line 257 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;} YY_BREAK case 59: YY_RULE_SETUP #line 258 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;} YY_BREAK case 60: YY_RULE_SETUP #line 259 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;} YY_BREAK case 61: YY_RULE_SETUP #line 260 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;} YY_BREAK case 62: YY_RULE_SETUP #line 261 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;} YY_BREAK case 63: YY_RULE_SETUP #line 262 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;} YY_BREAK case 64: YY_RULE_SETUP #line 263 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;} YY_BREAK case 65: YY_RULE_SETUP #line 264 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;} YY_BREAK case 66: YY_RULE_SETUP #line 265 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;} YY_BREAK case 67: YY_RULE_SETUP #line 266 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} YY_BREAK case 68: YY_RULE_SETUP #line 267 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} YY_BREAK case 69: YY_RULE_SETUP #line 268 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;} YY_BREAK case 70: YY_RULE_SETUP #line 269 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;} YY_BREAK case 71: YY_RULE_SETUP #line 270 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;} YY_BREAK case 72: YY_RULE_SETUP #line 271 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;} YY_BREAK case 73: YY_RULE_SETUP #line 272 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;} YY_BREAK case 74: YY_RULE_SETUP #line 273 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;} YY_BREAK case 75: YY_RULE_SETUP #line 274 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;} YY_BREAK case 76: YY_RULE_SETUP #line 275 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;} YY_BREAK case 77: YY_RULE_SETUP #line 276 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;} YY_BREAK case 78: YY_RULE_SETUP #line 277 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;} YY_BREAK case 79: YY_RULE_SETUP #line 278 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; } YY_BREAK case 80: YY_RULE_SETUP #line 279 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; } YY_BREAK case 81: YY_RULE_SETUP #line 280 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; } YY_BREAK case 82: YY_RULE_SETUP #line 281 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; } YY_BREAK case 83: YY_RULE_SETUP #line 282 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; } YY_BREAK case 84: YY_RULE_SETUP #line 283 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; } YY_BREAK case 85: YY_RULE_SETUP #line 284 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; } YY_BREAK case 86: YY_RULE_SETUP #line 285 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;} YY_BREAK case 87: YY_RULE_SETUP #line 286 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;} YY_BREAK case 88: YY_RULE_SETUP #line 287 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;} YY_BREAK case 89: YY_RULE_SETUP #line 288 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;} YY_BREAK case 90: YY_RULE_SETUP #line 289 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;} YY_BREAK case 91: YY_RULE_SETUP #line 290 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;} YY_BREAK case 92: YY_RULE_SETUP #line 291 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;} YY_BREAK case 93: YY_RULE_SETUP #line 292 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;} YY_BREAK case 94: YY_RULE_SETUP #line 293 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;} YY_BREAK case 95: /* rule 95 can match eol */ YY_RULE_SETUP #line 294 "configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK /* Quoted strings. Strip leading and ending quotes */ case 96: YY_RULE_SETUP #line 297 "configlexer.lex" { BEGIN(quotedstring); LEXOUT(("QS ")); } YY_BREAK case YY_STATE_EOF(quotedstring): #line 298 "configlexer.lex" { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } YY_BREAK case 97: YY_RULE_SETUP #line 302 "configlexer.lex" { LEXOUT(("STR(%s) ", yytext)); yymore(); } YY_BREAK case 98: /* rule 98 can match eol */ YY_RULE_SETUP #line 303 "configlexer.lex" { cfg_parser->line++; yymore(); } YY_BREAK case 99: YY_RULE_SETUP #line 304 "configlexer.lex" { LEXOUT(("QE ")); BEGIN(INITIAL); yytext[yyleng - 1] = '\0'; yylval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } YY_BREAK /* include: directive */ case 100: YY_RULE_SETUP #line 313 "configlexer.lex" { LEXOUT(("v(%s) ", yytext)); BEGIN(include); } YY_BREAK case YY_STATE_EOF(include): #line 314 "configlexer.lex" { yyerror("EOF inside include directive"); BEGIN(INITIAL); } YY_BREAK case 101: YY_RULE_SETUP #line 318 "configlexer.lex" { LEXOUT(("ISP ")); /* ignore */ } YY_BREAK case 102: /* rule 102 can match eol */ YY_RULE_SETUP #line 319 "configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK case 103: YY_RULE_SETUP #line 320 "configlexer.lex" { LEXOUT(("IQS ")); BEGIN(include_quoted); } YY_BREAK case 104: YY_RULE_SETUP #line 321 "configlexer.lex" { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext); BEGIN(INITIAL); } YY_BREAK case YY_STATE_EOF(include_quoted): #line 326 "configlexer.lex" { yyerror("EOF inside quoted string"); BEGIN(INITIAL); } YY_BREAK case 105: YY_RULE_SETUP #line 330 "configlexer.lex" { LEXOUT(("ISTR(%s) ", yytext)); yymore(); } YY_BREAK case 106: /* rule 106 can match eol */ YY_RULE_SETUP #line 331 "configlexer.lex" { cfg_parser->line++; yymore(); } YY_BREAK case 107: YY_RULE_SETUP #line 332 "configlexer.lex" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; config_start_include_glob(yytext); BEGIN(INITIAL); } YY_BREAK case YY_STATE_EOF(INITIAL): #line 338 "configlexer.lex" { yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ if (!config_include_stack) { yyterminate(); } else { fclose(yyin); config_end_include(); } } YY_BREAK case 108: YY_RULE_SETUP #line 348 "configlexer.lex" { LEXOUT(("unquotedstr(%s) ", yytext)); yylval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; } YY_BREAK case 109: YY_RULE_SETUP #line 351 "configlexer.lex" ECHO; YY_BREAK #line 2410 "" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,(yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,(yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 914 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 914 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; yy_is_jam = (yy_current_state == 913); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc((yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,(int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 351 "configlexer.lex" nsd-4.1.26/xfrd-tcp.c0000664000175000017500000007214413151260454013732 0ustar wouterwouter/* * xfrd-tcp.c - XFR (transfer) Daemon TCP system source file. Manages tcp conn. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include "nsd.h" #include "xfrd-tcp.h" #include "buffer.h" #include "packet.h" #include "dname.h" #include "options.h" #include "namedb.h" #include "xfrd.h" #include "xfrd-disk.h" #include "util.h" /* sort tcppipe, first on IP address, for an IPaddresss, sort on num_unused */ static int xfrd_pipe_cmp(const void* a, const void* b) { const struct xfrd_tcp_pipeline* x = (struct xfrd_tcp_pipeline*)a; const struct xfrd_tcp_pipeline* y = (struct xfrd_tcp_pipeline*)b; int r; if(x == y) return 0; if(y->ip_len != x->ip_len) /* subtraction works because nonnegative and small numbers */ return (int)y->ip_len - (int)x->ip_len; r = memcmp(&x->ip, &y->ip, x->ip_len); if(r != 0) return r; /* sort that num_unused is sorted ascending, */ if(x->num_unused != y->num_unused) { return (x->num_unused < y->num_unused) ? -1 : 1; } /* different pipelines are different still, even with same numunused*/ return (uintptr_t)x < (uintptr_t)y ? -1 : 1; } struct xfrd_tcp_set* xfrd_tcp_set_create(struct region* region) { int i; struct xfrd_tcp_set* tcp_set = region_alloc(region, sizeof(struct xfrd_tcp_set)); memset(tcp_set, 0, sizeof(struct xfrd_tcp_set)); tcp_set->tcp_count = 0; tcp_set->tcp_waiting_first = 0; tcp_set->tcp_waiting_last = 0; for(i=0; itcp_state[i] = xfrd_tcp_pipeline_create(region); tcp_set->pipetree = rbtree_create(region, &xfrd_pipe_cmp); return tcp_set; } struct xfrd_tcp_pipeline* xfrd_tcp_pipeline_create(region_type* region) { int i; struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*) region_alloc_zero(region, sizeof(*tp)); tp->num_unused = ID_PIPE_NUM; assert(sizeof(tp->unused)/sizeof(tp->unused[0]) == ID_PIPE_NUM); for(i=0; iunused[i] = (uint16_t)i; tp->tcp_r = xfrd_tcp_create(region, QIOBUFSZ); tp->tcp_w = xfrd_tcp_create(region, 512); return tp; } void xfrd_setup_packet(buffer_type* packet, uint16_t type, uint16_t klass, const dname_type* dname, uint16_t qid) { /* Set up the header */ buffer_clear(packet); ID_SET(packet, qid); FLAGS_SET(packet, 0); OPCODE_SET(packet, OPCODE_QUERY); QDCOUNT_SET(packet, 1); ANCOUNT_SET(packet, 0); NSCOUNT_SET(packet, 0); ARCOUNT_SET(packet, 0); buffer_skip(packet, QHEADERSZ); /* The question record. */ buffer_write(packet, dname_name(dname), dname->name_size); buffer_write_u16(packet, type); buffer_write_u16(packet, klass); } static socklen_t #ifdef INET6 xfrd_acl_sockaddr(acl_options_type* acl, unsigned int port, struct sockaddr_storage *sck) #else xfrd_acl_sockaddr(acl_options_type* acl, unsigned int port, struct sockaddr_in *sck, const char* fromto) #endif /* INET6 */ { /* setup address structure */ #ifdef INET6 memset(sck, 0, sizeof(struct sockaddr_storage)); #else memset(sck, 0, sizeof(struct sockaddr_in)); #endif if(acl->is_ipv6) { #ifdef INET6 struct sockaddr_in6* sa = (struct sockaddr_in6*)sck; sa->sin6_family = AF_INET6; sa->sin6_port = htons(port); sa->sin6_addr = acl->addr.addr6; return sizeof(struct sockaddr_in6); #else log_msg(LOG_ERR, "xfrd: IPv6 connection %s %s attempted but no \ INET6.", fromto, acl->ip_address_spec); return 0; #endif } else { struct sockaddr_in* sa = (struct sockaddr_in*)sck; sa->sin_family = AF_INET; sa->sin_port = htons(port); sa->sin_addr = acl->addr.addr; return sizeof(struct sockaddr_in); } } socklen_t #ifdef INET6 xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_storage *to) #else xfrd_acl_sockaddr_to(acl_options_type* acl, struct sockaddr_in *to) #endif /* INET6 */ { unsigned int port = acl->port?acl->port:(unsigned)atoi(TCP_PORT); #ifdef INET6 return xfrd_acl_sockaddr(acl, port, to); #else return xfrd_acl_sockaddr(acl, port, to, "to"); #endif /* INET6 */ } socklen_t #ifdef INET6 xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_storage *frm) #else xfrd_acl_sockaddr_frm(acl_options_type* acl, struct sockaddr_in *frm) #endif /* INET6 */ { unsigned int port = acl->port?acl->port:0; #ifdef INET6 return xfrd_acl_sockaddr(acl, port, frm); #else return xfrd_acl_sockaddr(acl, port, frm, "from"); #endif /* INET6 */ } void xfrd_write_soa_buffer(struct buffer* packet, const dname_type* apex, struct xfrd_soa* soa) { size_t rdlength_pos; uint16_t rdlength; buffer_write(packet, dname_name(apex), apex->name_size); /* already in network order */ buffer_write(packet, &soa->type, sizeof(soa->type)); buffer_write(packet, &soa->klass, sizeof(soa->klass)); buffer_write(packet, &soa->ttl, sizeof(soa->ttl)); rdlength_pos = buffer_position(packet); buffer_skip(packet, sizeof(rdlength)); /* uncompressed dnames */ buffer_write(packet, soa->prim_ns+1, soa->prim_ns[0]); buffer_write(packet, soa->email+1, soa->email[0]); buffer_write(packet, &soa->serial, sizeof(uint32_t)); buffer_write(packet, &soa->refresh, sizeof(uint32_t)); buffer_write(packet, &soa->retry, sizeof(uint32_t)); buffer_write(packet, &soa->expire, sizeof(uint32_t)); buffer_write(packet, &soa->minimum, sizeof(uint32_t)); /* write length of RR */ rdlength = buffer_position(packet) - rdlength_pos - sizeof(rdlength); buffer_write_u16_at(packet, rdlength_pos, rdlength); } struct xfrd_tcp* xfrd_tcp_create(region_type* region, size_t bufsize) { struct xfrd_tcp* tcp_state = (struct xfrd_tcp*)region_alloc( region, sizeof(struct xfrd_tcp)); memset(tcp_state, 0, sizeof(struct xfrd_tcp)); tcp_state->packet = buffer_create(region, bufsize); tcp_state->fd = -1; return tcp_state; } static struct xfrd_tcp_pipeline* pipeline_find(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { rbnode_type* sme = NULL; struct xfrd_tcp_pipeline* r; /* smaller buf than a full pipeline with 64kb ID array, only need * the front part with the key info, this front part contains the * members that the compare function uses. */ const size_t keysize = sizeof(struct xfrd_tcp_pipeline) - ID_PIPE_NUM*(sizeof(struct xfrd_zone*) + sizeof(uint16_t)); /* void* type for alignment of the struct, * divide the keysize by ptr-size and then add one to round up */ void* buf[ (keysize / sizeof(void*)) + 1 ]; struct xfrd_tcp_pipeline* key = (struct xfrd_tcp_pipeline*)buf; key->node.key = key; key->ip_len = xfrd_acl_sockaddr_to(zone->master, &key->ip); key->num_unused = ID_PIPE_NUM; /* lookup existing tcp transfer to the master with highest unused */ if(rbtree_find_less_equal(set->pipetree, key, &sme)) { /* exact match, strange, fully unused tcp cannot be open */ assert(0); } if(!sme) return NULL; r = (struct xfrd_tcp_pipeline*)sme->key; /* <= key pointed at, is the master correct ? */ if(r->ip_len != key->ip_len) return NULL; if(memcmp(&r->ip, &key->ip, key->ip_len) != 0) return NULL; /* correct master, is there a slot free for this transfer? */ if(r->num_unused == 0) return NULL; return r; } /* remove zone from tcp waiting list */ static void tcp_zone_waiting_list_popfirst(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { assert(zone->tcp_waiting); set->tcp_waiting_first = zone->tcp_waiting_next; if(zone->tcp_waiting_next) zone->tcp_waiting_next->tcp_waiting_prev = NULL; else set->tcp_waiting_last = 0; zone->tcp_waiting_next = 0; zone->tcp_waiting = 0; } /* remove zone from tcp pipe write-wait list */ static void tcp_pipe_sendlist_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { if(zone->in_tcp_send) { if(zone->tcp_send_prev) zone->tcp_send_prev->tcp_send_next=zone->tcp_send_next; else tp->tcp_send_first=zone->tcp_send_next; if(zone->tcp_send_next) zone->tcp_send_next->tcp_send_prev=zone->tcp_send_prev; else tp->tcp_send_last=zone->tcp_send_prev; zone->in_tcp_send = 0; } } /* remove first from write-wait list */ static void tcp_pipe_sendlist_popfirst(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { tp->tcp_send_first = zone->tcp_send_next; if(tp->tcp_send_first) tp->tcp_send_first->tcp_send_prev = NULL; else tp->tcp_send_last = NULL; zone->in_tcp_send = 0; } /* remove zone from tcp pipe ID map */ static void tcp_pipe_id_remove(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { assert(tp->num_unused < ID_PIPE_NUM && tp->num_unused >= 0); assert(tp->id[zone->query_id] == zone); tp->id[zone->query_id] = NULL; tp->unused[tp->num_unused] = zone->query_id; /* must remove and re-add for sort order in tree */ (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->node); tp->num_unused++; (void)rbtree_insert(xfrd->tcp_set->pipetree, &tp->node); } /* stop the tcp pipe (and all its zones need to retry) */ static void xfrd_tcp_pipe_stop(struct xfrd_tcp_pipeline* tp) { int i, conn = -1; assert(tp->num_unused < ID_PIPE_NUM); /* at least one 'in-use' */ assert(ID_PIPE_NUM - tp->num_unused > tp->num_skip); /* at least one 'nonskip' */ /* need to retry for all the zones connected to it */ /* these could use different lists and go to a different nextmaster*/ for(i=0; iid[i] && tp->id[i] != TCP_NULL_SKIP) { xfrd_zone_type* zone = tp->id[i]; conn = zone->tcp_conn; zone->tcp_conn = -1; zone->tcp_waiting = 0; tcp_pipe_sendlist_remove(tp, zone); tcp_pipe_id_remove(tp, zone); xfrd_set_refresh_now(zone); } } assert(conn != -1); /* now release the entire tcp pipe */ xfrd_tcp_pipe_release(xfrd->tcp_set, tp, conn); } static void tcp_pipe_reset_timeout(struct xfrd_tcp_pipeline* tp) { int fd = tp->handler.ev_fd; struct timeval tv; tv.tv_sec = xfrd->tcp_set->tcp_timeout; tv.tv_usec = 0; if(tp->handler_added) event_del(&tp->handler); event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ| (tp->tcp_send_first?EV_WRITE:0), xfrd_handle_tcp_pipe, tp); if(event_base_set(xfrd->event_base, &tp->handler) != 0) log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); if(event_add(&tp->handler, &tv) != 0) log_msg(LOG_ERR, "xfrd tcp: event_add failed"); tp->handler_added = 1; } /* handle event from fd of tcp pipe */ void xfrd_handle_tcp_pipe(int ATTR_UNUSED(fd), short event, void* arg) { struct xfrd_tcp_pipeline* tp = (struct xfrd_tcp_pipeline*)arg; if((event & EV_WRITE)) { tcp_pipe_reset_timeout(tp); if(tp->tcp_send_first) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp write, zone %s", tp->tcp_send_first->apex_str)); xfrd_tcp_write(tp, tp->tcp_send_first); } } if((event & EV_READ) && tp->handler_added) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp read")); tcp_pipe_reset_timeout(tp); xfrd_tcp_read(tp); } if((event & EV_TIMEOUT) && tp->handler_added) { /* tcp connection timed out */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: event tcp timeout")); xfrd_tcp_pipe_stop(tp); } } /* add a zone to the pipeline, it starts to want to write its query */ static void pipeline_setup_new_zone(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { /* assign the ID */ int idx; assert(tp->num_unused > 0); /* we pick a random ID, even though it is TCP anyway */ idx = random_generate(tp->num_unused); zone->query_id = tp->unused[idx]; tp->unused[idx] = tp->unused[tp->num_unused-1]; tp->id[zone->query_id] = zone; /* decrement unused counter, and fixup tree */ (void)rbtree_delete(set->pipetree, &tp->node); tp->num_unused--; (void)rbtree_insert(set->pipetree, &tp->node); /* add to sendlist, at end */ zone->tcp_send_next = NULL; zone->tcp_send_prev = tp->tcp_send_last; zone->in_tcp_send = 1; if(tp->tcp_send_last) tp->tcp_send_last->tcp_send_next = zone; else tp->tcp_send_first = zone; tp->tcp_send_last = zone; /* is it first in line? */ if(tp->tcp_send_first == zone) { xfrd_tcp_setup_write_packet(tp, zone); /* add write to event handler */ tcp_pipe_reset_timeout(tp); } } void xfrd_tcp_obtain(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { struct xfrd_tcp_pipeline* tp; assert(zone->tcp_conn == -1); assert(zone->tcp_waiting == 0); if(set->tcp_count < XFRD_MAX_TCP) { int i; assert(!set->tcp_waiting_first); set->tcp_count ++; /* find a free tcp_buffer */ for(i=0; itcp_state[i]->tcp_r->fd == -1) { zone->tcp_conn = i; break; } } /** What if there is no free tcp_buffer? return; */ if (zone->tcp_conn < 0) { return; } tp = set->tcp_state[zone->tcp_conn]; zone->tcp_waiting = 0; /* stop udp use (if any) */ if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); if(!xfrd_tcp_open(set, tp, zone)) { zone->tcp_conn = -1; set->tcp_count --; xfrd_set_refresh_now(zone); return; } /* ip and ip_len set by tcp_open */ tp->node.key = tp; tp->num_unused = ID_PIPE_NUM; tp->num_skip = 0; tp->tcp_send_first = NULL; tp->tcp_send_last = NULL; memset(tp->id, 0, sizeof(tp->id)); for(i=0; iunused[i] = i; } /* insert into tree */ (void)rbtree_insert(set->pipetree, &tp->node); xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* check for a pipeline to the same master with unused ID */ if((tp = pipeline_find(set, zone))!= NULL) { int i; if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); for(i=0; itcp_state[i] == tp) zone->tcp_conn = i; } xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* wait, at end of line */ DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfrd: max number of tcp " "connections (%d) reached.", XFRD_MAX_TCP)); zone->tcp_waiting_next = 0; zone->tcp_waiting_prev = set->tcp_waiting_last; zone->tcp_waiting = 1; if(!set->tcp_waiting_last) { set->tcp_waiting_first = zone; set->tcp_waiting_last = zone; } else { set->tcp_waiting_last->tcp_waiting_next = zone; set->tcp_waiting_last = zone; } xfrd_deactivate_zone(zone); xfrd_unset_timer(zone); } int xfrd_tcp_open(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { int fd, family, conn; struct timeval tv; assert(zone->tcp_conn != -1); /* if there is no next master, fallback to use the first one */ /* but there really should be a master set */ if(!zone->master) { zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s open tcp conn to %s", zone->apex_str, zone->master->ip_address_spec)); tp->tcp_r->is_reading = 1; tp->tcp_r->total_bytes = 0; tp->tcp_r->msglen = 0; buffer_clear(tp->tcp_r->packet); tp->tcp_w->is_reading = 0; tp->tcp_w->total_bytes = 0; tp->tcp_w->msglen = 0; tp->connection_established = 0; if(zone->master->is_ipv6) { #ifdef INET6 family = PF_INET6; #else xfrd_set_refresh_now(zone); return 0; #endif } else { family = PF_INET; } fd = socket(family, SOCK_STREAM, IPPROTO_TCP); if(fd == -1) { /* squelch 'Address family not supported by protocol' at low * verbosity levels */ if(errno != EAFNOSUPPORT || verbosity > 2) log_msg(LOG_ERR, "xfrd: %s cannot create tcp socket: %s", zone->master->ip_address_spec, strerror(errno)); xfrd_set_refresh_now(zone); return 0; } if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { log_msg(LOG_ERR, "xfrd: fcntl failed: %s", strerror(errno)); close(fd); xfrd_set_refresh_now(zone); return 0; } if(xfrd->nsd->outgoing_tcp_mss > 0) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void*)&xfrd->nsd->outgoing_tcp_mss, sizeof(xfrd->nsd->outgoing_tcp_mss)) < 0) { log_msg(LOG_ERR, "xfrd: setsockopt(TCP_MAXSEG)" "failed: %s", strerror(errno)); } #else log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported"); #endif } tp->ip_len = xfrd_acl_sockaddr_to(zone->master, &tp->ip); /* bind it */ if (!xfrd_bind_local_interface(fd, zone->zone_options->pattern-> outgoing_interface, zone->master, 1)) { close(fd); xfrd_set_refresh_now(zone); return 0; } conn = connect(fd, (struct sockaddr*)&tp->ip, tp->ip_len); if (conn == -1 && errno != EINPROGRESS) { log_msg(LOG_ERR, "xfrd: connect %s failed: %s", zone->master->ip_address_spec, strerror(errno)); close(fd); xfrd_set_refresh_now(zone); return 0; } tp->tcp_r->fd = fd; tp->tcp_w->fd = fd; /* set the tcp pipe event */ if(tp->handler_added) event_del(&tp->handler); event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|EV_WRITE, xfrd_handle_tcp_pipe, tp); if(event_base_set(xfrd->event_base, &tp->handler) != 0) log_msg(LOG_ERR, "xfrd tcp: event_base_set failed"); tv.tv_sec = set->tcp_timeout; tv.tv_usec = 0; if(event_add(&tp->handler, &tv) != 0) log_msg(LOG_ERR, "xfrd tcp: event_add failed"); tp->handler_added = 1; return 1; } void xfrd_tcp_setup_write_packet(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { struct xfrd_tcp* tcp = tp->tcp_w; assert(zone->tcp_conn != -1); assert(zone->tcp_waiting == 0); /* start AXFR or IXFR for the zone */ if(zone->soa_disk_acquired == 0 || zone->master->use_axfr_only || zone->master->ixfr_disabled || /* if zone expired, after the first round, do not ask for * IXFR any more, but full AXFR (of any serial number) */ (zone->state == xfrd_zone_expired && zone->round_num != 0)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request full zone transfer " "(AXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); xfrd_setup_packet(tcp->packet, TYPE_AXFR, CLASS_IN, zone->apex, zone->query_id); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request incremental zone " "transfer (IXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); xfrd_setup_packet(tcp->packet, TYPE_IXFR, CLASS_IN, zone->apex, zone->query_id); NSCOUNT_SET(tcp->packet, 1); xfrd_write_soa_buffer(tcp->packet, zone->apex, &zone->soa_disk); } /* old transfer needs to be removed still? */ if(zone->msg_seq_nr) xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber); zone->msg_seq_nr = 0; zone->msg_rr_count = 0; if(zone->master->key_options && zone->master->key_options->tsig_key) { xfrd_tsig_sign_request(tcp->packet, &zone->tsig, zone->master); } buffer_flip(tcp->packet); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "sent tcp query with ID %d", zone->query_id)); tcp->msglen = buffer_limit(tcp->packet); tcp->total_bytes = 0; } static void tcp_conn_ready_for_reading(struct xfrd_tcp* tcp) { tcp->total_bytes = 0; tcp->msglen = 0; buffer_clear(tcp->packet); } int conn_write(struct xfrd_tcp* tcp) { ssize_t sent; if(tcp->total_bytes < sizeof(tcp->msglen)) { uint16_t sendlen = htons(tcp->msglen); #ifdef HAVE_WRITEV struct iovec iov[2]; iov[0].iov_base = (uint8_t*)&sendlen + tcp->total_bytes; iov[0].iov_len = sizeof(sendlen) - tcp->total_bytes; iov[1].iov_base = buffer_begin(tcp->packet); iov[1].iov_len = buffer_limit(tcp->packet); sent = writev(tcp->fd, iov, 2); #else /* HAVE_WRITEV */ sent = write(tcp->fd, (const char*)&sendlen + tcp->total_bytes, sizeof(tcp->msglen) - tcp->total_bytes); #endif /* HAVE_WRITEV */ if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } tcp->total_bytes += sent; if(sent > (ssize_t)sizeof(tcp->msglen)) buffer_skip(tcp->packet, sent-sizeof(tcp->msglen)); if(tcp->total_bytes < sizeof(tcp->msglen)) { /* incomplete write, resume later */ return 0; } #ifdef HAVE_WRITEV if(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen)) { /* packet done */ return 1; } #endif assert(tcp->total_bytes >= sizeof(tcp->msglen)); } assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)); sent = write(tcp->fd, buffer_current(tcp->packet), buffer_remaining(tcp->packet)); if(sent == -1) { if(errno == EAGAIN || errno == EINTR) { /* write would block, try later */ return 0; } else { return -1; } } buffer_skip(tcp->packet, sent); tcp->total_bytes += sent; if(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) { /* more to write when socket becomes writable again */ return 0; } assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen)); return 1; } void xfrd_tcp_write(struct xfrd_tcp_pipeline* tp, xfrd_zone_type* zone) { int ret; struct xfrd_tcp* tcp = tp->tcp_w; assert(zone->tcp_conn != -1); assert(zone == tp->tcp_send_first); /* see if for non-established connection, there is a connect error */ if(!tp->connection_established) { /* check for pending error from nonblocking connect */ /* from Stevens, unix network programming, vol1, 3rd ed, p450 */ int error = 0; socklen_t len = sizeof(error); if(getsockopt(tcp->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){ error = errno; /* on solaris errno is error */ } if(error == EINPROGRESS || error == EWOULDBLOCK) return; /* try again later */ if(error != 0) { log_msg(LOG_ERR, "%s: Could not tcp connect to %s: %s", zone->apex_str, zone->master->ip_address_spec, strerror(error)); xfrd_tcp_pipe_stop(tp); return; } } ret = conn_write(tcp); if(ret == -1) { log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno)); xfrd_tcp_pipe_stop(tp); return; } if(tcp->total_bytes != 0 && !tp->connection_established) tp->connection_established = 1; if(ret == 0) { return; /* write again later */ } /* done writing this message */ /* remove first zone from sendlist */ tcp_pipe_sendlist_popfirst(tp, zone); /* see if other zone wants to write; init; let it write (now) */ /* and use a loop, because 64k stack calls is a too much */ while(tp->tcp_send_first) { /* setup to write for this zone */ xfrd_tcp_setup_write_packet(tp, tp->tcp_send_first); /* attempt to write for this zone (if success, continue loop)*/ ret = conn_write(tcp); if(ret == -1) { log_msg(LOG_ERR, "xfrd: failed writing tcp %s", strerror(errno)); xfrd_tcp_pipe_stop(tp); return; } if(ret == 0) return; /* write again later */ tcp_pipe_sendlist_popfirst(tp, tp->tcp_send_first); } /* if sendlist empty, remove WRITE from event */ /* listen to READ, and not WRITE events */ assert(tp->tcp_send_first == NULL); tcp_pipe_reset_timeout(tp); } int conn_read(struct xfrd_tcp* tcp) { ssize_t received; /* receive leading packet length bytes */ if(tcp->total_bytes < sizeof(tcp->msglen)) { received = read(tcp->fd, (char*) &tcp->msglen + tcp->total_bytes, sizeof(tcp->msglen) - tcp->total_bytes); if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tcp read sz: %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; if(tcp->total_bytes < sizeof(tcp->msglen)) { /* not complete yet, try later */ return 0; } assert(tcp->total_bytes == sizeof(tcp->msglen)); tcp->msglen = ntohs(tcp->msglen); if(tcp->msglen == 0) { buffer_set_limit(tcp->packet, tcp->msglen); return 1; } if(tcp->msglen > buffer_capacity(tcp->packet)) { log_msg(LOG_ERR, "buffer too small, dropping connection"); return 0; } buffer_set_limit(tcp->packet, tcp->msglen); } assert(buffer_remaining(tcp->packet) > 0); received = read(tcp->fd, buffer_current(tcp->packet), buffer_remaining(tcp->packet)); if(received == -1) { if(errno == EAGAIN || errno == EINTR) { /* read would block, try later */ return 0; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "tcp read %s", strerror(errno)); return -1; } } else if(received == 0) { /* EOF */ return -1; } tcp->total_bytes += received; buffer_skip(tcp->packet, received); if(buffer_remaining(tcp->packet) > 0) { /* not complete yet, wait for more */ return 0; } /* completed */ assert(buffer_position(tcp->packet) == tcp->msglen); return 1; } void xfrd_tcp_read(struct xfrd_tcp_pipeline* tp) { xfrd_zone_type* zone; struct xfrd_tcp* tcp = tp->tcp_r; int ret; enum xfrd_packet_result pkt_result; ret = conn_read(tcp); if(ret == -1) { xfrd_tcp_pipe_stop(tp); return; } if(ret == 0) return; /* completed msg */ buffer_flip(tcp->packet); /* see which ID number it is, if skip, handle skip, NULL: warn */ if(tcp->msglen < QHEADERSZ) { /* too short for DNS header, skip it */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp skip response that is too short")); tcp_conn_ready_for_reading(tcp); return; } zone = tp->id[ID(tcp->packet)]; if(!zone || zone == TCP_NULL_SKIP) { /* no zone for this id? skip it */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp skip response with %s ID", zone?"set-to-skip":"unknown")); tcp_conn_ready_for_reading(tcp); return; } assert(zone->tcp_conn != -1); /* handle message for zone */ pkt_result = xfrd_handle_received_xfr_packet(zone, tcp->packet); /* setup for reading the next packet on this connection */ tcp_conn_ready_for_reading(tcp); switch(pkt_result) { case xfrd_packet_more: /* wait for next packet */ break; case xfrd_packet_newlease: /* set to skip if more packets with this ID */ 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); xfrd_make_request(zone); break; } xfrd_tcp_release(xfrd->tcp_set, zone); assert(zone->round_num == -1); break; case xfrd_packet_notimpl: xfrd_disable_ixfr(zone); xfrd_tcp_release(xfrd->tcp_set, zone); /* query next server */ xfrd_make_request(zone); break; case xfrd_packet_bad: case xfrd_packet_tcp: default: /* set to skip if more packets with this ID */ tp->id[zone->query_id] = TCP_NULL_SKIP; tp->num_skip++; xfrd_tcp_release(xfrd->tcp_set, zone); /* query next server */ xfrd_make_request(zone); break; } } void xfrd_tcp_release(struct xfrd_tcp_set* set, xfrd_zone_type* zone) { int conn = zone->tcp_conn; struct xfrd_tcp_pipeline* tp = set->tcp_state[conn]; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s released tcp conn to %s", zone->apex_str, zone->master->ip_address_spec)); assert(zone->tcp_conn != -1); assert(zone->tcp_waiting == 0); zone->tcp_conn = -1; zone->tcp_waiting = 0; /* remove from tcp_send list */ tcp_pipe_sendlist_remove(tp, zone); /* remove it from the ID list */ if(tp->id[zone->query_id] != TCP_NULL_SKIP) tcp_pipe_id_remove(tp, zone); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: released tcp pipe now %d unused", tp->num_unused)); /* if pipe was full, but no more, then see if waiting element is * for the same master, and can fill the unused ID */ if(tp->num_unused == 1 && set->tcp_waiting_first) { #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif socklen_t to_len = xfrd_acl_sockaddr_to( set->tcp_waiting_first->master, &to); if(to_len == tp->ip_len && memcmp(&to, &tp->ip, to_len) == 0) { /* use this connection for the waiting zone */ zone = set->tcp_waiting_first; assert(zone->tcp_conn == -1); zone->tcp_conn = conn; tcp_zone_waiting_list_popfirst(set, zone); if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); return; } /* waiting zone did not go to same server */ } /* if all unused, or only skipped leftover, close the pipeline */ if(tp->num_unused >= ID_PIPE_NUM || tp->num_skip >= ID_PIPE_NUM - tp->num_unused) xfrd_tcp_pipe_release(set, tp, conn); } void xfrd_tcp_pipe_release(struct xfrd_tcp_set* set, struct xfrd_tcp_pipeline* tp, int conn) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: tcp pipe released")); /* one handler per tcp pipe */ if(tp->handler_added) event_del(&tp->handler); tp->handler_added = 0; /* fd in tcp_r and tcp_w is the same, close once */ if(tp->tcp_r->fd != -1) close(tp->tcp_r->fd); tp->tcp_r->fd = -1; tp->tcp_w->fd = -1; /* remove from pipetree */ (void)rbtree_delete(xfrd->tcp_set->pipetree, &tp->node); /* a waiting zone can use the free tcp slot (to another server) */ /* if that zone fails to set-up or connect, we try to start the next * waiting zone in the list */ while(set->tcp_count == XFRD_MAX_TCP && set->tcp_waiting_first) { int i; /* pop first waiting process */ xfrd_zone_type* zone = set->tcp_waiting_first; /* start it */ assert(zone->tcp_conn == -1); zone->tcp_conn = conn; tcp_zone_waiting_list_popfirst(set, zone); /* stop udp (if any) */ if(zone->zone_handler.ev_fd != -1) xfrd_udp_release(zone); if(!xfrd_tcp_open(set, tp, zone)) { zone->tcp_conn = -1; xfrd_set_refresh_now(zone); /* try to start the next zone (if any) */ continue; } /* re-init this tcppipe */ /* ip and ip_len set by tcp_open */ tp->node.key = tp; tp->num_unused = ID_PIPE_NUM; tp->num_skip = 0; tp->tcp_send_first = NULL; tp->tcp_send_last = NULL; memset(tp->id, 0, sizeof(tp->id)); for(i=0; iunused[i] = i; } /* insert into tree */ (void)rbtree_insert(set->pipetree, &tp->node); /* setup write */ xfrd_unset_timer(zone); pipeline_setup_new_zone(set, tp, zone); /* started a task, no need for cleanups, so return */ return; } /* no task to start, cleanup */ assert(!set->tcp_waiting_first); set->tcp_count --; assert(set->tcp_count >= 0); } nsd-4.1.26/buffer.h0000664000175000017500000002254412736741576013501 0ustar wouterwouter/* * buffer.h -- generic memory buffer. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * * * The buffer module implements a generic buffer. The API is based on * the java.nio.Buffer interface. */ #ifndef _BUFFER_H_ #define _BUFFER_H_ #include #include #include #include "region-allocator.h" #include "util.h" typedef struct buffer buffer_type; struct buffer { /* * The current position used for reading/writing. */ size_t _position; /* * The read/write limit. */ size_t _limit; /* * The amount of data the buffer can contain. */ size_t _capacity; /* * The data contained in the buffer. */ uint8_t *_data; /* * If the buffer is fixed it cannot be resized. */ unsigned _fixed : 1; }; #ifdef NDEBUG static inline void buffer_invariant(buffer_type *ATTR_UNUSED(buffer)) { } #else static inline void buffer_invariant(buffer_type *buffer) { assert(buffer); assert(buffer->_position <= buffer->_limit); assert(buffer->_limit <= buffer->_capacity); assert(buffer->_data); } #endif /* * Create a new buffer with the specified capacity. */ buffer_type *buffer_create(region_type *region, size_t capacity); /* * Create a buffer with the specified data. The data is not copied * and no memory allocations are done. The buffer is fixed and cannot * be resized using buffer_reserve(). */ void buffer_create_from(buffer_type *buffer, void *data, size_t size); /* * Clear the buffer and make it ready for writing. The buffer's limit * is set to the capacity and the position is set to 0. */ void buffer_clear(buffer_type *buffer); /* * Make the buffer ready for reading the data that has been written to * the buffer. The buffer's limit is set to the current position and * the position is set to 0. */ void buffer_flip(buffer_type *buffer); /* * Make the buffer ready for re-reading the data. The buffer's * position is reset to 0. */ void buffer_rewind(buffer_type *buffer); static inline size_t buffer_position(buffer_type *buffer) { return buffer->_position; } /* * Set the buffer's position to MARK. The position must be less than * or equal to the buffer's limit. */ static inline void buffer_set_position(buffer_type *buffer, size_t mark) { assert(mark <= buffer->_limit); buffer->_position = mark; } /* * Change the buffer's position by COUNT bytes. The position must not * be moved behind the buffer's limit or before the beginning of the * buffer. */ static inline void buffer_skip(buffer_type *buffer, ssize_t count) { assert(buffer->_position + count <= buffer->_limit); buffer->_position += count; } static inline size_t buffer_limit(buffer_type *buffer) { return buffer->_limit; } /* * Change the buffer's limit. If the buffer's position is greater * than the new limit the position is set to the limit. */ static inline void buffer_set_limit(buffer_type *buffer, size_t limit) { assert(limit <= buffer->_capacity); buffer->_limit = limit; if (buffer->_position > buffer->_limit) buffer->_position = buffer->_limit; } static inline size_t buffer_capacity(buffer_type *buffer) { return buffer->_capacity; } /* * Change the buffer's capacity. The data is reallocated so any * pointers to the data may become invalid. The buffer's limit is set * to the buffer's new capacity. */ void buffer_set_capacity(buffer_type *buffer, size_t capacity); /* * Ensure BUFFER can contain at least AMOUNT more bytes. The buffer's * capacity is increased if necessary using buffer_set_capacity(). * * The buffer's limit is always set to the (possibly increased) * capacity. */ void buffer_reserve(buffer_type *buffer, size_t amount); /* * Return a pointer to the data at the indicated position. */ static inline uint8_t * buffer_at(buffer_type *buffer, size_t at) { assert(at <= buffer->_limit); return buffer->_data + at; } /* * Return a pointer to the beginning of the buffer (the data at * position 0). */ static inline uint8_t * buffer_begin(buffer_type *buffer) { return buffer_at(buffer, 0); } /* * Return a pointer to the end of the buffer (the data at the buffer's * limit). */ static inline uint8_t * buffer_end(buffer_type *buffer) { return buffer_at(buffer, buffer->_limit); } /* * Return a pointer to the data at the buffer's current position. */ static inline uint8_t * buffer_current(buffer_type *buffer) { return buffer_at(buffer, buffer->_position); } /* * The number of bytes remaining between the indicated position and * the limit. */ static inline size_t buffer_remaining_at(buffer_type *buffer, size_t at) { buffer_invariant(buffer); assert(at <= buffer->_limit); return buffer->_limit - at; } /* * The number of bytes remaining between the buffer's position and * limit. */ static inline size_t buffer_remaining(buffer_type *buffer) { return buffer_remaining_at(buffer, buffer->_position); } /* * Check if the buffer has at least COUNT more bytes available. * Before reading or writing the caller needs to ensure enough space * is available! */ static inline int buffer_available_at(buffer_type *buffer, size_t at, size_t count) { return count <= buffer_remaining_at(buffer, at); } static inline int buffer_available(buffer_type *buffer, size_t count) { return buffer_available_at(buffer, buffer->_position, count); } static inline void buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) { assert(buffer_available_at(buffer, at, count)); memcpy(buffer->_data + at, data, count); } static inline void buffer_write(buffer_type *buffer, const void *data, size_t count) { buffer_write_at(buffer, buffer->_position, data, count); buffer->_position += count; } static inline void buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) { buffer_write_at(buffer, at, str, strlen(str)); } static inline void buffer_write_string(buffer_type *buffer, const char *str) { buffer_write(buffer, str, strlen(str)); } static inline void buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); buffer->_data[at] = data; } static inline void buffer_write_u8(buffer_type *buffer, uint8_t data) { buffer_write_u8_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint16(buffer->_data + at, data); } static inline void buffer_write_u16(buffer_type *buffer, uint16_t data) { buffer_write_u16_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint32(buffer->_data + at, data); } static inline void buffer_write_u32(buffer_type *buffer, uint32_t data) { buffer_write_u32_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) { assert(buffer_available_at(buffer, at, sizeof(data))); write_uint64(buffer->_data + at, data); } static inline void buffer_write_u64(buffer_type *buffer, uint64_t data) { buffer_write_u64_at(buffer, buffer->_position, data); buffer->_position += sizeof(data); } static inline void buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) { assert(buffer_available_at(buffer, at, count)); memcpy(data, buffer->_data + at, count); } static inline void buffer_read(buffer_type *buffer, void *data, size_t count) { buffer_read_at(buffer, buffer->_position, data, count); buffer->_position += count; } static inline uint8_t buffer_read_u8_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint8_t))); return buffer->_data[at]; } static inline uint8_t buffer_read_u8(buffer_type *buffer) { uint8_t result = buffer_read_u8_at(buffer, buffer->_position); buffer->_position += sizeof(uint8_t); return result; } static inline uint16_t buffer_read_u16_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint16_t))); return read_uint16(buffer->_data + at); } static inline uint16_t buffer_read_u16(buffer_type *buffer) { uint16_t result = buffer_read_u16_at(buffer, buffer->_position); buffer->_position += sizeof(uint16_t); return result; } static inline uint32_t buffer_read_u32_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint32_t))); return read_uint32(buffer->_data + at); } static inline uint32_t buffer_read_u32(buffer_type *buffer) { uint32_t result = buffer_read_u32_at(buffer, buffer->_position); buffer->_position += sizeof(uint32_t); return result; } static inline uint64_t buffer_read_u64_at(buffer_type *buffer, size_t at) { assert(buffer_available_at(buffer, at, sizeof(uint64_t))); return read_uint64(buffer->_data + at); } static inline uint64_t buffer_read_u64(buffer_type *buffer) { uint64_t result = buffer_read_u64_at(buffer, buffer->_position); buffer->_position += sizeof(uint64_t); return result; } /* * Print to the buffer, increasing the capacity if required using * buffer_reserve(). The buffer's position is set to the terminating * '\0'. Returns the number of characters written (not including the * terminating '\0'). */ int buffer_printf(buffer_type *buffer, const char *format, ...) ATTR_FORMAT(printf, 2, 3); #endif /* _BUFFER_H_ */ nsd-4.1.26/xfrd-disk.c0000664000175000017500000004102113272617055014073 0ustar wouterwouter/* * xfrd-disk.c - XFR (transfer) Daemon TCP system source file. Read/Write state to disk. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include #include #include #include #include #include "xfrd-disk.h" #include "xfrd.h" #include "buffer.h" #include "nsd.h" #include "options.h" /* quick tokenizer, reads words separated by whitespace. No quoted strings. Comments are skipped (#... eol). */ static char* xfrd_read_token(FILE* in) { static char buf[4000]; buf[sizeof(buf)-1]=0; while(1) { if(fscanf(in, " %3990s", buf) != 1) return 0; if(buf[0] != '#') return buf; if(!fgets(buf, sizeof(buf), in)) return 0; } } static int xfrd_read_i16(FILE *in, uint16_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atoi(p); return 1; } static int xfrd_read_i32(FILE *in, uint32_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atoi(p); return 1; } static int xfrd_read_time_t(FILE *in, time_t* v) { char* p = xfrd_read_token(in); if(!p) return 0; *v=atol(p); return 1; } static int xfrd_read_check_str(FILE* in, const char* str) { char *p = xfrd_read_token(in); if(!p) return 0; if(strcmp(p, str) != 0) return 0; return 1; } static int xfrd_read_state_soa(FILE* in, const char* id_acquired, const char* id, xfrd_soa_type* soa, time_t* soatime) { char *p; if(!xfrd_read_check_str(in, id_acquired) || !xfrd_read_time_t(in, soatime)) { return 0; } if(*soatime == 0) return 1; if(!xfrd_read_check_str(in, id) || !xfrd_read_i16(in, &soa->type) || !xfrd_read_i16(in, &soa->klass) || !xfrd_read_i32(in, &soa->ttl) || !xfrd_read_i16(in, &soa->rdata_count)) { return 0; } soa->type = htons(soa->type); soa->klass = htons(soa->klass); soa->ttl = htonl(soa->ttl); soa->rdata_count = htons(soa->rdata_count); if(!(p=xfrd_read_token(in)) || !(soa->prim_ns[0] = dname_parse_wire(soa->prim_ns+1, p))) return 0; if(!(p=xfrd_read_token(in)) || !(soa->email[0] = dname_parse_wire(soa->email+1, p))) return 0; if(!xfrd_read_i32(in, &soa->serial) || !xfrd_read_i32(in, &soa->refresh) || !xfrd_read_i32(in, &soa->retry) || !xfrd_read_i32(in, &soa->expire) || !xfrd_read_i32(in, &soa->minimum)) { return 0; } soa->serial = htonl(soa->serial); soa->refresh = htonl(soa->refresh); soa->retry = htonl(soa->retry); soa->expire = htonl(soa->expire); soa->minimum = htonl(soa->minimum); return 1; } void xfrd_read_state(struct xfrd_state* xfrd) { const char* statefile = xfrd->nsd->options->xfrdfile; FILE *in; uint32_t filetime = 0; uint32_t numzones, i; region_type *tempregion; time_t soa_refresh; tempregion = region_create(xalloc, free); if(!tempregion) return; in = fopen(statefile, "r"); if(!in) { if(errno != ENOENT) { log_msg(LOG_ERR, "xfrd: Could not open file %s for reading: %s", statefile, strerror(errno)); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: no file %s. refreshing all zones.", statefile)); } region_destroy(tempregion); return; } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) { /* older file version; reset everything */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: file %s is old version. refreshing all zones.", statefile)); fclose(in); region_destroy(tempregion); return; } if(!xfrd_read_check_str(in, "filetime:") || !xfrd_read_i32(in, &filetime) || (time_t)filetime > xfrd_time()+15 || !xfrd_read_check_str(in, "numzones:") || !xfrd_read_i32(in, &numzones)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } for(i=0; i2) || !xfrd_read_check_str(in, "master:") || !xfrd_read_i32(in, &masnum) || !xfrd_read_check_str(in, "next_master:") || !xfrd_read_i32(in, &nextmas) || !xfrd_read_check_str(in, "round_num:") || !xfrd_read_i32(in, &round_num) || !xfrd_read_check_str(in, "next_timeout:") || !xfrd_read_i32(in, &timeout) || !xfrd_read_check_str(in, "backoff:") || !xfrd_read_i32(in, &backoff) || !xfrd_read_state_soa(in, "soa_nsd_acquired:", "soa_nsd:", &soa_nsd_read, &soa_nsd_acquired_read) || !xfrd_read_state_soa(in, "soa_disk_acquired:", "soa_disk:", &soa_disk_read, &soa_disk_acquired_read) || !xfrd_read_state_soa(in, "soa_notify_acquired:", "soa_notify:", &soa_notified_read, &soa_notified_acquired_read)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); fclose(in); region_destroy(tempregion); return; } zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, dname); if(!zone) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: state file has info for not configured zone %s", p)); continue; } if(soa_nsd_acquired_read>xfrd_time()+15 || soa_disk_acquired_read>xfrd_time()+15 || soa_notified_acquired_read>xfrd_time()+15) { log_msg(LOG_ERR, "xfrd: statefile %s contains" " times in the future for zone %s. Ignoring.", statefile, zone->apex_str); continue; } zone->state = state; zone->master_num = masnum; zone->next_master = nextmas; zone->round_num = round_num; zone->timeout.tv_sec = timeout; zone->timeout.tv_usec = 0; zone->fresh_xfr_timeout = backoff*XFRD_TRANSFER_TIMEOUT_START; /* read the zone OK, now set the master properly */ zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); if(!zone->master) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: masters changed for zone %s", zone->apex_str)); zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; zone->round_num = 0; } /* * There is no timeout, * or there is a notification, * or there is a soa && current time is past refresh point */ soa_refresh = ntohl(soa_disk_read.refresh); if (soa_refresh > (time_t)zone->zone_options->pattern->max_refresh_time) soa_refresh = zone->zone_options->pattern->max_refresh_time; else if (soa_refresh < (time_t)zone->zone_options->pattern->min_refresh_time) soa_refresh = zone->zone_options->pattern->min_refresh_time; if(timeout == 0 || soa_notified_acquired_read != 0 || (soa_disk_acquired_read != 0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > (uint32_t)soa_refresh)) { zone->state = xfrd_zone_refreshing; xfrd_set_refresh_now(zone); } /* There is a soa && current time is past expiry point */ if(soa_disk_acquired_read!=0 && (uint32_t)xfrd_time() - soa_disk_acquired_read > ntohl(soa_disk_read.expire)) { zone->state = xfrd_zone_expired; xfrd_set_refresh_now(zone); } /* there is a zone read and it matches what we had before */ if(zone->soa_nsd_acquired && zone->state != xfrd_zone_expired && zone->soa_nsd.serial == soa_nsd_read.serial) { xfrd_deactivate_zone(zone); zone->state = state; xfrd_set_timer(zone, timeout); } if((zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 && soa_disk_acquired_read == 0) || (zone->state != xfrd_zone_ok && timeout != 0)) { /* but don't check now, because that would mean a * storm of attempts on some master servers */ xfrd_deactivate_zone(zone); zone->state = state; xfrd_set_timer(zone, timeout); } /* handle as an incoming SOA. */ incoming_soa = zone->soa_nsd; incoming_acquired = zone->soa_nsd_acquired; zone->soa_nsd = soa_nsd_read; zone->soa_disk = soa_disk_read; zone->soa_notified = soa_notified_read; zone->soa_nsd_acquired = soa_nsd_acquired_read; /* we had better use what we got from starting NSD, not * what we store in this file, because the actual zone * contents trumps the contents of this cache */ /* zone->soa_disk_acquired = soa_disk_acquired_read; */ zone->soa_notified_acquired = soa_notified_acquired_read; if (zone->state == xfrd_zone_expired) { xfrd_send_expire_notification(zone); } if(incoming_acquired != 0) xfrd_handle_incoming_soa(zone, &incoming_soa, incoming_acquired); } if(!xfrd_read_check_str(in, XFRD_FILE_MAGIC)) { log_msg(LOG_ERR, "xfrd: corrupt state file %s dated %d (now=%lld)", statefile, (int)filetime, (long long)xfrd_time()); region_destroy(tempregion); fclose(in); return; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: read %d zones from state file", (int)numzones)); fclose(in); region_destroy(tempregion); } /* prints neato days hours and minutes. */ static void neato_timeout(FILE* out, const char* str, time_t secs) { fprintf(out, "%s", str); if(secs <= 0) { fprintf(out, " %llds", (long long)secs); return; } if(secs >= 3600*24) { fprintf(out, " %lldd", (long long)(secs/(3600*24))); secs = secs % (3600*24); } if(secs >= 3600) { fprintf(out, " %lldh", (long long)(secs/3600)); secs = secs%3600; } if(secs >= 60) { fprintf(out, " %lldm", (long long)(secs/60)); secs = secs%60; } if(secs > 0) { fprintf(out, " %llds", (long long)secs); } } static void xfrd_write_dname(FILE* out, uint8_t* dname) { uint8_t* d= dname+1; uint8_t len = *d++; uint8_t i; if(dname[0]<=1) { fprintf(out, "."); return; } while(len) { assert(d - (dname+1) <= dname[0]); for(i=0; itype), (unsigned)ntohs(soa->klass), (unsigned)ntohl(soa->ttl), (unsigned)ntohs(soa->rdata_count)); fprintf(out, " "); xfrd_write_dname(out, soa->prim_ns); fprintf(out, " "); xfrd_write_dname(out, soa->email); fprintf(out, " %u", (unsigned)ntohl(soa->serial)); fprintf(out, " %u", (unsigned)ntohl(soa->refresh)); fprintf(out, " %u", (unsigned)ntohl(soa->retry)); fprintf(out, " %u", (unsigned)ntohl(soa->expire)); fprintf(out, " %u\n", (unsigned)ntohl(soa->minimum)); fprintf(out, "\t#"); neato_timeout(out, " refresh =", ntohl(soa->refresh)); neato_timeout(out, " retry =", ntohl(soa->retry)); neato_timeout(out, " expire =", ntohl(soa->expire)); neato_timeout(out, " minimum =", ntohl(soa->minimum)); fprintf(out, "\n"); } void xfrd_write_state(struct xfrd_state* xfrd) { rbnode_type* p; const char* statefile = xfrd->nsd->options->xfrdfile; FILE *out; time_t now = xfrd_time(); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: write file %s", statefile)); out = fopen(statefile, "w"); if(!out) { log_msg(LOG_ERR, "xfrd: Could not open file %s for writing: %s", statefile, strerror(errno)); return; } fprintf(out, "%s\n", XFRD_FILE_MAGIC); fprintf(out, "# This file is written on exit by nsd xfr daemon.\n"); fprintf(out, "# This file contains slave zone information:\n"); fprintf(out, "# * timeouts (when was zone data acquired)\n"); fprintf(out, "# * state (OK, refreshing, expired)\n"); fprintf(out, "# * which master transfer to attempt next\n"); fprintf(out, "# The file is read on start (but not on reload) by nsd xfr daemon.\n"); fprintf(out, "# You can edit; but do not change statement order\n"); fprintf(out, "# and no fancy stuff (like quoted \"strings\").\n"); fprintf(out, "#\n"); fprintf(out, "# If you remove a zone entry, it will be refreshed.\n"); fprintf(out, "# This can be useful for an expired zone; it revives\n"); fprintf(out, "# the zone temporarily, from refresh-expiry time.\n"); fprintf(out, "# If you delete the file all slave zones are updated.\n"); fprintf(out, "#\n"); fprintf(out, "# Note: if you edit this file while nsd is running,\n"); fprintf(out, "# it will be overwritten on exit by nsd.\n"); fprintf(out, "\n"); fprintf(out, "filetime: %lld\t# %s\n", (long long)now, ctime(&now)); fprintf(out, "# The number of zone entries in this file\n"); fprintf(out, "numzones: %d\n", (int)xfrd->zones->count); fprintf(out, "\n"); for(p = rbtree_first(xfrd->zones); p && p!=RBTREE_NULL; p=rbtree_next(p)) { xfrd_zone_type* zone = (xfrd_zone_type*)p; fprintf(out, "zone: \tname: %s\n", zone->apex_str); fprintf(out, "\tstate: %d", (int)zone->state); fprintf(out, " # %s", zone->state==xfrd_zone_ok?"OK":( zone->state==xfrd_zone_refreshing?"refreshing":"expired")); fprintf(out, "\n"); fprintf(out, "\tmaster: %d\n", zone->master_num); fprintf(out, "\tnext_master: %d\n", zone->next_master); fprintf(out, "\tround_num: %d\n", zone->round_num); fprintf(out, "\tnext_timeout: %d", (zone->zone_handler_flags&EV_TIMEOUT)?(int)zone->timeout.tv_sec:0); if((zone->zone_handler_flags&EV_TIMEOUT)) { neato_timeout(out, "\t# =", zone->timeout.tv_sec); } fprintf(out, "\n"); fprintf(out, "\tbackoff: %d\n", zone->fresh_xfr_timeout/XFRD_TRANSFER_TIMEOUT_START); xfrd_write_state_soa(out, "soa_nsd", &zone->soa_nsd, zone->soa_nsd_acquired, zone->apex); xfrd_write_state_soa(out, "soa_disk", &zone->soa_disk, zone->soa_disk_acquired, zone->apex); xfrd_write_state_soa(out, "soa_notify", &zone->soa_notified, zone->soa_notified_acquired, zone->apex); fprintf(out, "\n"); } fprintf(out, "%s\n", XFRD_FILE_MAGIC); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: written %d zones to state file", (int)xfrd->zones->count)); fclose(out); } /* return tempdirname */ static void tempdirname(char* buf, size_t sz, struct nsd* nsd) { snprintf(buf, sz, "%snsd-xfr-%d", nsd->options->xfrdir, (int)nsd->pid); } void xfrd_make_tempdir(struct nsd* nsd) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); /* create parent directories if needed (0750 permissions) */ if(!create_dirs(tnm)) { log_msg(LOG_ERR, "parentdirs of %s failed", tnm); } /* restrictive permissions here, because this may be in /tmp */ if(mkdir(tnm, 0700)==-1) { if(errno != EEXIST) { log_msg(LOG_ERR, "mkdir %s failed: %s", tnm, strerror(errno)); } } } void xfrd_del_tempdir(struct nsd* nsd) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); /* ignore parent directories, they are likely /var/tmp, /tmp or * /var/cache/nsd and do not have to be deleted */ if(rmdir(tnm)==-1 && errno != ENOENT) { log_msg(LOG_WARNING, "rmdir %s failed: %s", tnm, strerror(errno)); } } /* return name of xfrfile in tempdir */ static void tempxfrname(char* buf, size_t sz, struct nsd* nsd, uint64_t number) { char tnm[1024]; tempdirname(tnm, sizeof(tnm), nsd); snprintf(buf, sz, "%s/xfr.%lld", tnm, (long long)number); } FILE* xfrd_open_xfrfile(struct nsd* nsd, uint64_t number, char* mode) { char fname[1200]; FILE* xfr; tempxfrname(fname, sizeof(fname), nsd, number); xfr = fopen(fname, mode); if(!xfr && errno == ENOENT) { /* directory may not exist */ xfrd_make_tempdir(nsd); xfr = fopen(fname, mode); } if(!xfr) { log_msg(LOG_ERR, "open %s for %s failed: %s", fname, mode, strerror(errno)); return NULL; } return xfr; } void xfrd_unlink_xfrfile(struct nsd* nsd, uint64_t number) { char fname[1200]; tempxfrname(fname, sizeof(fname), nsd, number); if(unlink(fname) == -1) { log_msg(LOG_WARNING, "could not unlink %s: %s", fname, strerror(errno)); } } uint64_t xfrd_get_xfrfile_size(struct nsd* nsd, uint64_t number ) { char fname[1200]; struct stat tempxfr_stat; tempxfrname(fname, sizeof(fname), nsd, number); if( stat( fname, &tempxfr_stat ) < 0 ) { log_msg(LOG_WARNING, "could not get file size %s: %s", fname, strerror(errno)); return 0; } return (uint64_t)tempxfr_stat.st_size; } nsd-4.1.26/tsig.c0000664000175000017500000004171213327535543013157 0ustar wouterwouter/* * tsig.c -- TSIG implementation (RFC 2845). * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include #include "tsig.h" #include "tsig-openssl.h" #include "dns.h" #include "packet.h" #include "query.h" #include "rbtree.h" static region_type *tsig_region; struct tsig_key_table { rbnode_type node; /* by dname */ tsig_key_type *key; }; typedef struct tsig_key_table tsig_key_table_type; static rbtree_type *tsig_key_table; struct tsig_algorithm_table { struct tsig_algorithm_table *next; tsig_algorithm_type *algorithm; }; typedef struct tsig_algorithm_table tsig_algorithm_table_type; static tsig_algorithm_table_type *tsig_algorithm_table; static size_t max_algo_digest_size = 0; static void tsig_digest_variables(tsig_record_type *tsig, int tsig_timers_only) { uint16_t klass = htons(CLASS_ANY); uint32_t ttl = htonl(0); uint16_t signed_time_high = htons(tsig->signed_time_high); uint32_t signed_time_low = htonl(tsig->signed_time_low); uint16_t signed_time_fudge = htons(tsig->signed_time_fudge); uint16_t error_code = htons(tsig->error_code); uint16_t other_size = htons(tsig->other_size); if (!tsig_timers_only) { tsig->algorithm->hmac_update(tsig->context, dname_name(tsig->key_name), tsig->key_name->name_size); tsig->algorithm->hmac_update(tsig->context, &klass, sizeof(klass)); tsig->algorithm->hmac_update(tsig->context, &ttl, sizeof(ttl)); tsig->algorithm->hmac_update(tsig->context, dname_name(tsig->algorithm_name), tsig->algorithm_name->name_size); } tsig->algorithm->hmac_update(tsig->context, &signed_time_high, sizeof(signed_time_high)); tsig->algorithm->hmac_update(tsig->context, &signed_time_low, sizeof(signed_time_low)); tsig->algorithm->hmac_update(tsig->context, &signed_time_fudge, sizeof(signed_time_fudge)); if (!tsig_timers_only) { tsig->algorithm->hmac_update(tsig->context, &error_code, sizeof(error_code)); tsig->algorithm->hmac_update(tsig->context, &other_size, sizeof(other_size)); tsig->algorithm->hmac_update(tsig->context, tsig->other_data, tsig->other_size); } } static int tree_dname_compare(const void* a, const void* b) { return dname_compare((const dname_type*)a, (const dname_type*)b); } int tsig_init(region_type *region) { tsig_region = region; tsig_key_table = rbtree_create(region, &tree_dname_compare); tsig_algorithm_table = NULL; #if defined(HAVE_SSL) return tsig_openssl_init(region); #endif /* defined(HAVE_SSL) */ return 1; } void tsig_add_key(tsig_key_type *key) { tsig_key_table_type *entry = (tsig_key_table_type *) region_alloc_zero( tsig_region, sizeof(tsig_key_table_type)); entry->key = key; entry->node.key = entry->key->name; (void)rbtree_insert(tsig_key_table, &entry->node); } void tsig_del_key(tsig_key_type *key) { tsig_key_table_type *entry; if(!key) return; entry = (tsig_key_table_type*)rbtree_delete(tsig_key_table, key->name); if(!entry) return; region_recycle(tsig_region, entry, sizeof(tsig_key_table_type)); } tsig_key_type* tsig_find_key(const dname_type* name) { tsig_key_table_type* entry; entry = (tsig_key_table_type*)rbtree_search(tsig_key_table, name); if(entry) return entry->key; return NULL; } void tsig_add_algorithm(tsig_algorithm_type *algorithm) { tsig_algorithm_table_type *entry = (tsig_algorithm_table_type *) region_alloc( tsig_region, sizeof(tsig_algorithm_table_type)); entry->algorithm = algorithm; entry->next = tsig_algorithm_table; tsig_algorithm_table = entry; if(algorithm->maximum_digest_size > max_algo_digest_size) max_algo_digest_size = algorithm->maximum_digest_size; } /** * compare a tsig algorithm string lowercased */ int tsig_strlowercmp(const char* str1, const char* str2) { while (str1 && str2 && *str1 != '\0' && *str2 != '\0') { if(tolower((unsigned char)*str1) != tolower((unsigned char)*str2)) { if(tolower((unsigned char)*str1) < tolower((unsigned char)*str2)) return -1; return 1; } str1++; str2++; } if (str1 && str2) { if (*str1 == *str2) return 0; else if (*str1 == '\0') return -1; } else if (!str1 && !str2) return 0; else if (!str1 && str2) return -1; return 1; } /* * Find an HMAC algorithm based on its short name. */ tsig_algorithm_type * tsig_get_algorithm_by_name(const char *name) { tsig_algorithm_table_type *algorithm_entry; for (algorithm_entry = tsig_algorithm_table; algorithm_entry; algorithm_entry = algorithm_entry->next) { if (tsig_strlowercmp(name, algorithm_entry->algorithm->short_name) == 0) { return algorithm_entry->algorithm; } if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) == 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) { return algorithm_entry->algorithm; } } return NULL; } const char * tsig_error(int error_code) { static char message[1000]; switch (error_code) { case TSIG_ERROR_NOERROR: return "No Error"; break; case TSIG_ERROR_BADSIG: return "Bad Signature"; break; case TSIG_ERROR_BADKEY: return "Bad Key"; break; case TSIG_ERROR_BADTIME: return "Bad Time"; break; default: if(error_code < 16) /* DNS rcodes */ return rcode2str(error_code); snprintf(message, sizeof(message), "Unknown Error %d", error_code); break; } return message; } static void tsig_cleanup(void *data) { tsig_record_type *tsig = (tsig_record_type *) data; region_destroy(tsig->rr_region); region_destroy(tsig->context_region); } void tsig_create_record(tsig_record_type *tsig, region_type *region) { tsig_create_record_custom(tsig, region, DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE); } void tsig_create_record_custom(tsig_record_type *tsig, region_type *region, size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size) { tsig->rr_region = region_create_custom(xalloc, free, chunk_size, large_object_size, initial_cleanup_size, 0); tsig->context_region = region_create_custom(xalloc, free, chunk_size, large_object_size, initial_cleanup_size, 0); if(region) region_add_cleanup(region, tsig_cleanup, tsig); tsig_init_record(tsig, NULL, NULL); } void tsig_delete_record(tsig_record_type* tsig, region_type* region) { if(region) region_remove_cleanup(region, tsig_cleanup, tsig); region_destroy(tsig->rr_region); region_destroy(tsig->context_region); } void tsig_init_record(tsig_record_type *tsig, tsig_algorithm_type *algorithm, tsig_key_type *key) { tsig->status = TSIG_NOT_PRESENT; tsig->error_code = TSIG_ERROR_NOERROR; tsig->position = 0; tsig->response_count = 0; tsig->context = NULL; tsig->algorithm = algorithm; tsig->key = key; tsig->prior_mac_size = 0; tsig->prior_mac_data = NULL; region_free_all(tsig->context_region); } int tsig_from_query(tsig_record_type *tsig) { tsig_key_type *key = NULL; tsig_algorithm_table_type *algorithm_entry; tsig_algorithm_type *algorithm = NULL; uint64_t current_time; uint64_t signed_time; assert(tsig->status == TSIG_OK); assert(!tsig->algorithm); assert(!tsig->key); key = (tsig_key_type*)tsig_find_key(tsig->key_name); for (algorithm_entry = tsig_algorithm_table; algorithm_entry; algorithm_entry = algorithm_entry->next) { if (dname_compare( tsig->algorithm_name, algorithm_entry->algorithm->wireformat_name) == 0) { algorithm = algorithm_entry->algorithm; break; } } if (!algorithm || !key) { /* Algorithm or key is unknown, cannot authenticate. */ tsig->error_code = TSIG_ERROR_BADKEY; return 0; } if ((tsig->algorithm && algorithm != tsig->algorithm) || (tsig->key && key != tsig->key)) { /* * Algorithm or key changed during a single connection, * return error. */ tsig->error_code = TSIG_ERROR_BADKEY; return 0; } signed_time = ((((uint64_t) tsig->signed_time_high) << 32) | ((uint64_t) tsig->signed_time_low)); current_time = (uint64_t) time(NULL); if ((current_time < signed_time - tsig->signed_time_fudge) || (current_time > signed_time + tsig->signed_time_fudge)) { uint16_t current_time_high; uint32_t current_time_low; #if 0 /* debug */ char current_time_text[26]; char signed_time_text[26]; time_t clock; clock = (time_t) current_time; ctime_r(&clock, current_time_text); current_time_text[24] = '\0'; clock = (time_t) signed_time; ctime_r(&clock, signed_time_text); signed_time_text[24] = '\0'; log_msg(LOG_ERR, "current server time %s is outside the range of TSIG" " signed time %s with fudge %u", current_time_text, signed_time_text, (unsigned) tsig->signed_time_fudge); #endif tsig->error_code = TSIG_ERROR_BADTIME; current_time_high = (uint16_t) (current_time >> 32); current_time_low = (uint32_t) current_time; tsig->other_size = 6; tsig->other_data = (uint8_t *) region_alloc( tsig->rr_region, sizeof(uint16_t) + sizeof(uint32_t)); write_uint16(tsig->other_data, current_time_high); write_uint32(tsig->other_data + 2, current_time_low); return 0; } tsig->algorithm = algorithm; tsig->key = key; tsig->response_count = 0; tsig->prior_mac_size = 0; return 1; } void tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id) { assert(tsig); assert(tsig->algorithm); assert(tsig->key); tsig->response_count = 0; tsig->prior_mac_size = 0; tsig->algorithm_name = tsig->algorithm->wireformat_name; tsig->key_name = tsig->key->name; tsig->mac_size = 0; tsig->mac_data = NULL; tsig->original_query_id = original_query_id; tsig->error_code = TSIG_ERROR_NOERROR; tsig->other_size = 0; tsig->other_data = NULL; } void tsig_prepare(tsig_record_type *tsig) { if (!tsig->context) { assert(tsig->algorithm); tsig->context = tsig->algorithm->hmac_create_context( tsig->context_region); tsig->prior_mac_data = (uint8_t *) region_alloc( tsig->context_region, tsig->algorithm->maximum_digest_size); } tsig->algorithm->hmac_init_context(tsig->context, tsig->algorithm, tsig->key); if (tsig->prior_mac_size > 0) { uint16_t mac_size = htons(tsig->prior_mac_size); tsig->algorithm->hmac_update(tsig->context, &mac_size, sizeof(mac_size)); tsig->algorithm->hmac_update(tsig->context, tsig->prior_mac_data, tsig->prior_mac_size); } tsig->updates_since_last_prepare = 0; } void tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length) { uint16_t original_query_id = htons(tsig->original_query_id); assert(length <= buffer_limit(packet)); tsig->algorithm->hmac_update(tsig->context, &original_query_id, sizeof(original_query_id)); tsig->algorithm->hmac_update( tsig->context, buffer_at(packet, sizeof(original_query_id)), length - sizeof(original_query_id)); if (QR(packet)) { ++tsig->response_count; } ++tsig->updates_since_last_prepare; } void tsig_sign(tsig_record_type *tsig) { uint64_t current_time = (uint64_t) time(NULL); tsig->signed_time_high = (uint16_t) (current_time >> 32); tsig->signed_time_low = (uint32_t) current_time; tsig->signed_time_fudge = 300; /* XXX; hardcoded value */ tsig_digest_variables(tsig, tsig->response_count > 1); tsig->algorithm->hmac_final(tsig->context, tsig->prior_mac_data, &tsig->prior_mac_size); tsig->mac_size = tsig->prior_mac_size; tsig->mac_data = tsig->prior_mac_data; } int tsig_verify(tsig_record_type *tsig) { tsig_digest_variables(tsig, tsig->response_count > 1); tsig->algorithm->hmac_final(tsig->context, tsig->prior_mac_data, &tsig->prior_mac_size); if (tsig->mac_size != tsig->prior_mac_size || CRYPTO_memcmp(tsig->mac_data, tsig->prior_mac_data, tsig->mac_size) != 0) { /* Digest is incorrect, cannot authenticate. */ tsig->error_code = TSIG_ERROR_BADSIG; return 0; } else { return 1; } } int tsig_find_rr(tsig_record_type *tsig, buffer_type *packet) { size_t saved_position = buffer_position(packet); size_t rrcount = (QDCOUNT(packet) + ANCOUNT(packet) + NSCOUNT(packet) + ARCOUNT(packet)); size_t i; int result; if (ARCOUNT(packet) == 0) { tsig->status = TSIG_NOT_PRESENT; return 1; } buffer_set_position(packet, QHEADERSZ); /* TSIG must be the last record, so skip all others. */ for (i = 0; i < rrcount - 1; ++i) { if (!packet_skip_rr(packet, i < QDCOUNT(packet))) { buffer_set_position(packet, saved_position); return 0; } } result = tsig_parse_rr(tsig, packet); buffer_set_position(packet, saved_position); return result; } int tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet) { uint16_t type; uint16_t klass; uint32_t ttl; uint16_t rdlen; tsig->status = TSIG_NOT_PRESENT; tsig->position = buffer_position(packet); tsig->key_name = NULL; tsig->algorithm_name = NULL; tsig->mac_data = NULL; tsig->other_data = NULL; region_free_all(tsig->rr_region); tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1); if (!tsig->key_name) { buffer_set_position(packet, tsig->position); return 0; } if (!buffer_available(packet, 10)) { buffer_set_position(packet, tsig->position); return 0; } type = buffer_read_u16(packet); klass = buffer_read_u16(packet); /* TSIG not present */ if (type != TYPE_TSIG || klass != CLASS_ANY) { buffer_set_position(packet, tsig->position); return 1; } ttl = buffer_read_u32(packet); rdlen = buffer_read_u16(packet); tsig->status = TSIG_ERROR; tsig->error_code = RCODE_FORMAT; if (ttl != 0 || !buffer_available(packet, rdlen)) { buffer_set_position(packet, tsig->position); return 0; } tsig->algorithm_name = dname_make_from_packet( tsig->rr_region, packet, 1, 1); if (!tsig->algorithm_name || !buffer_available(packet, 10)) { buffer_set_position(packet, tsig->position); return 0; } tsig->signed_time_high = buffer_read_u16(packet); tsig->signed_time_low = buffer_read_u32(packet); tsig->signed_time_fudge = buffer_read_u16(packet); tsig->mac_size = buffer_read_u16(packet); if (!buffer_available(packet, tsig->mac_size)) { buffer_set_position(packet, tsig->position); tsig->mac_size = 0; return 0; } tsig->mac_data = (uint8_t *) region_alloc_init( tsig->rr_region, buffer_current(packet), tsig->mac_size); buffer_skip(packet, tsig->mac_size); if (!buffer_available(packet, 6)) { buffer_set_position(packet, tsig->position); return 0; } tsig->original_query_id = buffer_read_u16(packet); tsig->error_code = buffer_read_u16(packet); tsig->other_size = buffer_read_u16(packet); if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) { tsig->other_size = 0; buffer_set_position(packet, tsig->position); return 0; } tsig->other_data = (uint8_t *) region_alloc_init( tsig->rr_region, buffer_current(packet), tsig->other_size); buffer_skip(packet, tsig->other_size); tsig->status = TSIG_OK; return 1; } void tsig_append_rr(tsig_record_type *tsig, buffer_type *packet) { size_t rdlength_pos; /* XXX: TODO key name compression? */ if(tsig->key_name) buffer_write(packet, dname_name(tsig->key_name), tsig->key_name->name_size); else buffer_write_u8(packet, 0); buffer_write_u16(packet, TYPE_TSIG); buffer_write_u16(packet, CLASS_ANY); buffer_write_u32(packet, 0); /* TTL */ rdlength_pos = buffer_position(packet); buffer_skip(packet, sizeof(uint16_t)); if(tsig->algorithm_name) buffer_write(packet, dname_name(tsig->algorithm_name), tsig->algorithm_name->name_size); else buffer_write_u8(packet, 0); buffer_write_u16(packet, tsig->signed_time_high); buffer_write_u32(packet, tsig->signed_time_low); buffer_write_u16(packet, tsig->signed_time_fudge); buffer_write_u16(packet, tsig->mac_size); buffer_write(packet, tsig->mac_data, tsig->mac_size); buffer_write_u16(packet, tsig->original_query_id); buffer_write_u16(packet, tsig->error_code); buffer_write_u16(packet, tsig->other_size); buffer_write(packet, tsig->other_data, tsig->other_size); buffer_write_u16_at(packet, rdlength_pos, buffer_position(packet) - rdlength_pos - sizeof(uint16_t)); } size_t tsig_reserved_space(tsig_record_type *tsig) { if (tsig->status == TSIG_NOT_PRESENT) return 0; return ( (tsig->key_name?tsig->key_name->name_size:1) /* Owner */ + sizeof(uint16_t) /* Type */ + sizeof(uint16_t) /* Class */ + sizeof(uint32_t) /* TTL */ + sizeof(uint16_t) /* RDATA length */ + (tsig->algorithm_name?tsig->algorithm_name->name_size:1) + sizeof(uint16_t) /* Signed time (high) */ + sizeof(uint32_t) /* Signed time (low) */ + sizeof(uint16_t) /* Signed time fudge */ + sizeof(uint16_t) /* MAC size */ + max_algo_digest_size /* MAC data */ + sizeof(uint16_t) /* Original query ID */ + sizeof(uint16_t) /* Error code */ + sizeof(uint16_t) /* Other size */ + tsig->other_size); /* Other data */ } void tsig_error_reply(tsig_record_type *tsig) { if(tsig->mac_data) memset(tsig->mac_data, 0, tsig->mac_size); tsig->mac_size = 0; } void tsig_finalize() { #if defined(HAVE_SSL) tsig_openssl_finalize(); #endif /* defined(HAVE_SSL) */ } nsd-4.1.26/packet.c0000664000175000017500000002324113066176204013450 0ustar wouterwouter/* * packet.c -- low-level DNS packet encoding and decoding functions. * * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. * * See LICENSE for the license. * */ #include "config.h" #include #include "packet.h" #include "query.h" #include "rdata.h" int round_robin = 0; int minimal_responses = 0; static void encode_dname(query_type *q, domain_type *domain) { while (domain->parent && query_get_dname_offset(q, domain) == 0) { query_put_dname_offset(q, domain, buffer_position(q->packet)); DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", domain_to_string(domain), (unsigned long) domain->number, query_get_dname_offset(q, domain))); buffer_write(q->packet, dname_name(domain_dname(domain)), label_length(dname_name(domain_dname(domain))) + 1U); domain = domain->parent; } if (domain->parent) { DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", domain_to_string(domain), (unsigned long) domain->number, query_get_dname_offset(q, domain))); assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); buffer_write_u16(q->packet, 0xc000 | query_get_dname_offset(q, domain)); } else { buffer_write_u8(q->packet, 0); } } int packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr, uint32_t ttl) { size_t truncation_mark; uint16_t rdlength = 0; size_t rdlength_pos; uint16_t j; assert(q); assert(owner); assert(rr); /* * If the record does not in fit in the packet the packet size * will be restored to the mark. */ truncation_mark = buffer_position(q->packet); encode_dname(q, owner); buffer_write_u16(q->packet, rr->type); buffer_write_u16(q->packet, rr->klass); buffer_write_u32(q->packet, ttl); /* Reserve space for rdlength. */ rdlength_pos = buffer_position(q->packet); buffer_skip(q->packet, sizeof(rdlength)); for (j = 0; j < rr->rdata_count; ++j) { switch (rdata_atom_wireformat_type(rr->type, j)) { case RDATA_WF_COMPRESSED_DNAME: encode_dname(q, rdata_atom_domain(rr->rdatas[j])); break; case RDATA_WF_UNCOMPRESSED_DNAME: { const dname_type *dname = domain_dname( rdata_atom_domain(rr->rdatas[j])); buffer_write(q->packet, dname_name(dname), dname->name_size); break; } default: buffer_write(q->packet, rdata_atom_data(rr->rdatas[j]), rdata_atom_size(rr->rdatas[j])); break; } } if (!query_overflow(q)) { rdlength = (buffer_position(q->packet) - rdlength_pos - sizeof(rdlength)); buffer_write_u16_at(q->packet, rdlength_pos, rdlength); return 1; } else { buffer_set_position(q->packet, truncation_mark); query_clear_dname_offsets(q, truncation_mark); assert(!query_overflow(q)); return 0; } } int packet_encode_rrset(query_type *query, domain_type *owner, rrset_type *rrset, int section, #ifdef MINIMAL_RESPONSES size_t minimal_respsize, int* done) #else size_t ATTR_UNUSED(minimal_respsize), int* ATTR_UNUSED(done)) #endif { uint16_t i; size_t truncation_mark; uint16_t added = 0; int all_added = 1; #ifdef MINIMAL_RESPONSES int minimize_response = (section >= OPTIONAL_AUTHORITY_SECTION); int truncate_rrset = (section == ANSWER_SECTION || section == AUTHORITY_SECTION); #else int truncate_rrset = (section == ANSWER_SECTION || section == AUTHORITY_SECTION || section == OPTIONAL_AUTHORITY_SECTION); #endif static int round_robin_off = 0; int do_robin = (round_robin && section == ANSWER_SECTION && query->qtype != TYPE_AXFR && query->qtype != TYPE_IXFR); uint16_t start; rrset_type *rrsig; assert(rrset->rr_count > 0); truncation_mark = buffer_position(query->packet); if(do_robin && rrset->rr_count) start = (uint16_t)(round_robin_off++ % rrset->rr_count); else start = 0; for (i = start; i < rrset->rr_count; ++i) { if (packet_encode_rr(query, owner, &rrset->rrs[i], rrset->rrs[i].ttl)) { ++added; } else { all_added = 0; start = 0; break; } } for (i = 0; i < start; ++i) { if (packet_encode_rr(query, owner, &rrset->rrs[i], rrset->rrs[i].ttl)) { ++added; } else { all_added = 0; break; } } if (all_added && query->edns.dnssec_ok && zone_is_secure(rrset->zone) && rrset_rrtype(rrset) != TYPE_RRSIG && (rrsig = domain_find_rrset(owner, rrset->zone, TYPE_RRSIG))) { for (i = 0; i < rrsig->rr_count; ++i) { if (rr_rrsig_type_covered(&rrsig->rrs[i]) == rrset_rrtype(rrset)) { if (packet_encode_rr(query, owner, &rrsig->rrs[i], rrset_rrtype(rrset)==TYPE_SOA?rrset->rrs[0].ttl:rrsig->rrs[i].ttl)) { ++added; } else { all_added = 0; break; } } } } #ifdef MINIMAL_RESPONSES if ((!all_added || buffer_position(query->packet) > minimal_respsize) && !query->tcp && minimize_response) { /* Truncate entire RRset. */ buffer_set_position(query->packet, truncation_mark); query_clear_dname_offsets(query, truncation_mark); added = 0; *done = 1; } #endif if (!all_added && truncate_rrset) { /* Truncate entire RRset and set truncate flag. */ buffer_set_position(query->packet, truncation_mark); query_clear_dname_offsets(query, truncation_mark); TC_SET(query->packet); added = 0; } return added; } int packet_skip_dname(buffer_type *packet) { while (1) { uint8_t label_size; if (!buffer_available(packet, 1)) return 0; label_size = buffer_read_u8(packet); if (label_size == 0) { return 1; } else if ((label_size & 0xc0) != 0) { if (!buffer_available(packet, 1)) return 0; buffer_skip(packet, 1); return 1; } else if (!buffer_available(packet, label_size)) { return 0; } else { buffer_skip(packet, label_size); } } } int packet_skip_rr(buffer_type *packet, int question_section) { if (!packet_skip_dname(packet)) return 0; if (question_section) { if (!buffer_available(packet, 4)) return 0; buffer_skip(packet, 4); } else { uint16_t rdata_size; if (!buffer_available(packet, 10)) return 0; buffer_skip(packet, 8); rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) return 0; buffer_skip(packet, rdata_size); } return 1; } rr_type * packet_read_rr(region_type *region, domain_table_type *owners, buffer_type *packet, int question_section) { const dname_type *owner; uint16_t rdlength; ssize_t rdata_count; rdata_atom_type *rdatas; rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type)); owner = dname_make_from_packet(region, packet, 1, 1); if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) { return NULL; } result->owner = domain_table_insert(owners, owner); result->type = buffer_read_u16(packet); result->klass = buffer_read_u16(packet); if (question_section) { result->ttl = 0; result->rdata_count = 0; result->rdatas = NULL; return result; } else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) { return NULL; } result->ttl = buffer_read_u32(packet); rdlength = buffer_read_u16(packet); if (!buffer_available(packet, rdlength)) { return NULL; } rdata_count = rdata_wireformat_to_rdata_atoms( region, owners, result->type, rdlength, packet, &rdatas); if (rdata_count == -1) { return NULL; } result->rdata_count = rdata_count; result->rdatas = rdatas; return result; } int packet_read_query_section(buffer_type *packet, uint8_t* dst, uint16_t* qtype, uint16_t* qclass) { uint8_t *query_name = buffer_current(packet); uint8_t *src = query_name; size_t len; while (*src) { /* * If we are out of buffer limits or we have a pointer * in question dname or the domain name is longer than * MAXDOMAINLEN ... */ if ((*src & 0xc0) || (src + *src + 2 > buffer_end(packet)) || (src + *src + 2 > query_name + MAXDOMAINLEN)) { return 0; } memcpy(dst, src, *src + 1); dst += *src + 1; src += *src + 1; } *dst++ = *src++; /* Make sure name is not too long or we have stripped packet... */ len = src - query_name; if (len > MAXDOMAINLEN || (src + 2*sizeof(uint16_t) > buffer_end(packet))) { return 0; } buffer_set_position(packet, src - buffer_begin(packet)); *qtype = buffer_read_u16(packet); *qclass = buffer_read_u16(packet); return 1; } int packet_find_notify_serial(buffer_type *packet, uint32_t* serial) { size_t saved_position = buffer_position(packet); /* count of further RRs after question section */ size_t rrcount = ANCOUNT(packet) + NSCOUNT(packet) + ARCOUNT(packet); size_t i; buffer_set_position(packet, QHEADERSZ); /* skip all question RRs */ for (i = 0; i < QDCOUNT(packet); ++i) { if (!packet_skip_rr(packet, 1)) { buffer_set_position(packet, saved_position); return 0; } } /* Find the SOA RR */ for(i = 0; i < rrcount; i++) { uint16_t rdata_size; if (!packet_skip_dname(packet)) break; /* check length available for type,class,ttl,rdatalen */ if (!buffer_available(packet, 10)) break; /* check type, class */ if(buffer_read_u16(packet) == TYPE_SOA) { if(buffer_read_u16(packet) != CLASS_IN) break; buffer_skip(packet, 4); /* skip ttl */ rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) break; /* skip two dnames, then serial */ if (!packet_skip_dname(packet) || !packet_skip_dname(packet)) break; if (!buffer_available(packet, 4)) break; *serial = buffer_read_u32(packet); buffer_set_position(packet, saved_position); return 1; } /* continue to next RR */ buffer_skip(packet, 6); rdata_size = buffer_read_u16(packet); if (!buffer_available(packet, rdata_size)) break; buffer_skip(packet, rdata_size); } /* failed to find SOA */ buffer_set_position(packet, saved_position); return 0; } nsd-4.1.26/nsd.conf.sample.in0000664000175000017500000002550413355424715015365 0ustar wouterwouter# # nsd.conf -- the NSD(8) configuration file, nsd.conf(5). # # Copyright (c) 2001-2011, NLnet Labs. All rights reserved. # # See LICENSE for the license. # # This is a comment. # Sample configuration file # include: "file" # include that file's text over here. Globbed, "*.conf" # options for the nsd server server: # Number of NSD servers to fork. Put the number of CPUs to use here. # server-count: 1 # uncomment to specify specific interfaces to bind (default are the # wildcard interfaces 0.0.0.0 and ::0). # For servers with multiple IP addresses, list them one by one, # or the source address of replies could be wrong. # Use ip-transparent to be able to list addresses that turn on later. # ip-address: 1.2.3.4 # ip-address: 1.2.3.4@5678 # ip-address: 12fe::8ef0 # Allow binding to non local addresses. Default no. # ip-transparent: no # Allow binding to addresses that are down. Default no. # ip-freebind: no # use the reuseport socket option for performance. Default no. # reuseport: no # enable debug mode, does not fork daemon process into the background. # debug-mode: no # listen on IPv4 connections # do-ip4: yes # listen on IPv6 connections # do-ip6: yes # port to answer queries on. default is 53. # port: 53 # Verbosity level. # verbosity: 0 # After binding socket, drop user privileges. # can be a username, id or id.gid. # username: @user@ # Run NSD in a chroot-jail. # make sure to have pidfile and database reachable from there. # by default, no chroot-jail is used. # chroot: "@configdir@" # The directory for zonefile: files. The daemon chdirs here. # zonesdir: "@zonesdir@" # the list of dynamically added zones. # zonelistfile: "@zonelistfile@" # the database to use # if set to "" then no disk-database is used, less memory usage. # database: "@dbfile@" # log messages to file. Default to stderr and syslog (with # facility LOG_DAEMON). stderr disappears when daemon goes to bg. # logfile: "@logfile@" # File to store pid for nsd in. # pidfile: "@pidfile@" # The file where secondary zone refresh and expire timeouts are kept. # If you delete this file, all secondary zones are forced to be # 'refreshing' (as if nsd got a notify). Set to "" to disable. # xfrdfile: "@xfrdfile@" # The directory where zone transfers are stored, in a subdir of it. # xfrdir: "@xfrdir@" # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries # hide-version: no # version string the server responds with for chaos queries. # default is 'NSD x.y.z' with the server's version number. # version: "NSD" # identify the server (CH TXT ID.SERVER entry). # identity: "unidentified server" # NSID identity (hex string, or "ascii_somestring"). default disabled. # nsid: "aabbccdd" # Maximum number of concurrent TCP connections per server. # tcp-count: 100 # Maximum number of queries served on a single TCP connection. # By default 0, which means no maximum. # tcp-query-count: 0 # Override the default (120 seconds) TCP timeout. # tcp-timeout: 120 # Maximum segment size (MSS) of TCP socket on which the server # responds to queries. Default is 0, system default MSS. # tcp-mss: 0 # Maximum segment size (MSS) of TCP socket for outgoing AXFR request. # Default is 0, system default MSS. # outgoing-tcp-mss: 0 # Preferred EDNS buffer size for IPv4. # ipv4-edns-size: 4096 # Preferred EDNS buffer size for IPv6. # ipv6-edns-size: 4096 # statistics are produced every number of seconds. Prints to log. # Default is 0, meaning no statistics are produced. # statistics: 3600 # Number of seconds between reloads triggered by xfrd. # xfrd-reload-timeout: 1 # log timestamp in ascii (y-m-d h:m:s.msec), yes is default. # log-time-ascii: yes # round robin rotation of records in the answer. # round-robin: no # minimal-responses only emits extra data for referrals. # minimal-responses: no # refuse queries of type ANY. For stopping floods. # refuse-any: no # check mtime of all zone files on start and sighup # zonefiles-check: yes # write changed zonefiles to disk, every N seconds. # default is 0(disabled) or 3600(if database is ""). # zonefiles-write: 3600 # RRLconfig # Response Rate Limiting, size of the hashtable. Default 1000000. # rrl-size: 1000000 # Response Rate Limiting, maximum QPS allowed (from one query source). # If set to 0, ratelimiting is disabled. Also set # rrl-whitelist-ratelimit to 0 to disable ratelimit processing. # Default is @ratelimit_default@. # rrl-ratelimit: 200 # Response Rate Limiting, number of packets to discard before # sending a SLIP response (a truncated one, allowing an honest # resolver to retry with TCP). Default is 2 (one half of the # queries will receive a SLIP response, 0 disables SLIP (all # packets are discarded), 1 means every request will get a # SLIP response. When the ratelimit is hit the traffic is # divided by the rrl-slip value. # rrl-slip: 2 # Response Rate Limiting, IPv4 prefix length. Addresses are # grouped by netblock. # rrl-ipv4-prefix-length: 24 # Response Rate Limiting, IPv6 prefix length. Addresses are # grouped by netblock. # rrl-ipv6-prefix-length: 64 # Response Rate Limiting, maximum QPS allowed (from one query source) # for whitelisted types. Default is @ratelimit_default@. # rrl-whitelist-ratelimit: 2000 # RRLend # DNSTAP config section, if compiled with that # dnstap: # set this to yes and set one or more of dnstap-log-..-messages to yes. # dnstap-enable: no # dnstap-socket-path: "/var/run/dnstap.sock" # dnstap-send-identity: no # dnstap-send-version: no # dnstap-identity: "" # dnstap-version: "" # dnstap-log-auth-query-messages: no # dnstap-log-auth-response-messages: no # Remote control config section. remote-control: # Enable remote control with nsd-control(8) here. # set up the keys and certificates with nsd-control-setup. # control-enable: no # what interfaces are listened to for control, default is on localhost. # with an absolute path, a unix local named pipe is used for control # (and key and cert files are not needed, use directory permissions). # control-interface: 127.0.0.1 # control-interface: ::1 # port number for remote control operations (uses TLS over TCP). # control-port: 8952 # nsd server key file for remote control. # server-key-file: "@configdir@/nsd_server.key" # nsd server certificate file for remote control. # server-cert-file: "@configdir@/nsd_server.pem" # nsd-control key file. # control-key-file: "@configdir@/nsd_control.key" # nsd-control certificate file. # control-cert-file: "@configdir@/nsd_control.pem" # Secret keys for TSIGs that secure zone transfers. # You could include: "secret.keys" and put the 'key:' statements in there, # and give that file special access control permissions. # # key: # The key name is sent to the other party, it must be the same #name: "keyname" # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512 #algorithm: sha256 # secret material, must be the same as the other party uses. # base64 encoded random number. # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64 #secret: "K2tf3TRjvQkVCmJF3/Z9vA==" # Patterns have zone configuration and they are shared by one or more zones. # # pattern: # name by which the pattern is referred to #name: "myzones" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # If no master and slave access control elements are provided, # this zone will not be served to/from other servers. # A master zone needs notify: and provide-xfr: lists. A slave # may also allow zone transfer (for debug or other secondaries). # notify these slaves when the master zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. #notify: 192.0.2.1 NOKEY # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 #provide-xfr: 192.0.2.0/24 my_tsig_key_name # set the number of retries for notify. #notify-retry: 5 # uncomment to provide AXFR to all the world # provide-xfr: 0.0.0.0/0 NOKEY # provide-xfr: ::0/0 NOKEY # A slave zone needs allow-notify: and request-xfr: lists. #allow-notify: 2001:db8::0/64 my_tsig_key_name # By default, a slave will request a zone transfer with IXFR/TCP. # If you want to make use of IXFR/UDP use: UDP addr tsigkey # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey #request-xfr: 192.0.2.2 the_tsig_key_name # Attention: You cannot use UDP and AXFR together. AXFR is always over # TCP. If you use UDP, we higly recommend you to deploy TSIG. # Allow AXFR fallback if the master does not support IXFR. Default # is yes. #allow-axfr-fallback: yes # set local interface for sending zone transfer requests. # default is let the OS choose. #outgoing-interface: 10.0.0.10 # limit the refresh and retry interval in seconds. #max-refresh-time: 2419200 #min-refresh-time: 0 #max-retry-time: 1209600 #min-retry-time: 0 # Slave server tries zone transfer to all masters and picks highest # zone version available, for when masters have different versions. #multi-master-check: no # limit the zone transfer size (in bytes), stops very large transfers # 0 is no limits enforced. # size-limit-xfr: 0 # if compiled with --enable-zone-stats, give name of stat block for # this zone (or group of zones). Output from nsd-control stats. # zonestats: "%s" # if you give another pattern name here, at this point the settings # from that pattern are inserted into this one (as if it were a # macro). The statement can be given in between other statements, # because the order of access control elements can make a difference # (which master to request from first, which slave to notify first). #include-pattern: "common-masters" # Fixed zone entries. Here you can config zones that cannot be deleted. # Zones that are dynamically added and deleted are put in the zonelist file. # # zone: # name: "example.com" # you can give a pattern here, all the settings from that pattern # are then inserted at this point # include-pattern: "master" # You can also specify (additional) options directly for this zone. # zonefile: "example.com.zone" # request-xfr: 192.0.2.1 example.com.key # RRLconfig # Response Rate Limiting, whitelist types # rrl-whitelist: nxdomain # rrl-whitelist: error # rrl-whitelist: referral # rrl-whitelist: any # rrl-whitelist: rrsig # rrl-whitelist: wildcard # rrl-whitelist: nodata # rrl-whitelist: dnskey # rrl-whitelist: positive # rrl-whitelist: all # RRLend nsd-4.1.26/nsd-checkzone.8.in0000664000175000017500000000161613401455025015262 0ustar wouterwouter.TH "nsd\-checkzone" "8" "Dec 4, 2018" "NLnet Labs" "nsd 4.1.26" .\" Copyright (c) 2014, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd\-checkzone \- NSD zone file syntax checker. .SH "SYNOPSIS" .B nsd\-checkzone .RB [ \-h ] .I zonename .I zonefile .SH "DESCRIPTION" .B nsd\-checkzone reads a DNS zone file and checks it for errors. It prints errors to stderr. On failure it exits with nonzero exit status. .P This is used to check files before feeding them to the nsd(8) daemon. .SH "OPTIONS" .TP .B \-h Print usage help information and exit. .TP .I zonename The name of the zone to check, eg. "example.com". .TP .I zonefile The file to read, eg. "zones/example.com.zone.signed". .SH "SEE ALSO" \fInsd\fR(8), \fInsd-checkconf\fR(8) .SH "AUTHORS" .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details.