--- embedaddon/dnsmasq/src/cache.c 2013/07/29 19:37:40 1.1.1.1 +++ embedaddon/dnsmasq/src/cache.c 2014/06/15 16:31:38 1.1.1.2 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley 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 @@ -24,10 +24,6 @@ static struct crec *new_chain = NULL; static int cache_inserted = 0, cache_live_freed = 0, insert_error; static union bigname *big_free = NULL; static int bignames_left, hash_size; -static int uid = 0; -#ifdef HAVE_DNSSEC -static struct keydata *keyblock_free = NULL; -#endif /* type->string mapping: this is also used by the name-hash function as a mixing table. */ static const struct { @@ -56,7 +52,11 @@ static const struct { { 38, "A6" }, { 39, "DNAME" }, { 41, "OPT" }, + { 43, "DS" }, + { 46, "RRSIG" }, + { 47, "NSEC" }, { 48, "DNSKEY" }, + { 50, "NSEC3" }, { 249, "TKEY" }, { 250, "TSIG" }, { 251, "IXFR" }, @@ -72,11 +72,24 @@ static void cache_link(struct crec *crecp); static void rehash(int size); static void cache_hash(struct crec *crecp); +static unsigned int next_uid(void) +{ + static unsigned int uid = 0; + + uid++; + + /* uid == 0 used to indicate CNAME to interface name. */ + if (uid == SRC_INTERFACE) + uid++; + + return uid; +} + void cache_init(void) { struct crec *crecp; int i; - + bignames_left = daemon->cachesize/10; if (daemon->cachesize > 0) @@ -87,7 +100,7 @@ void cache_init(void) { cache_link(crecp); crecp->flags = 0; - crecp->uid = uid++; + crecp->uid = next_uid(); } } @@ -171,13 +184,28 @@ static void cache_hash(struct crec *crecp) crecp->hash_next = *up; *up = crecp; } - + +#ifdef HAVE_DNSSEC +static void cache_blockdata_free(struct crec *crecp) +{ + if (crecp->flags & F_DNSKEY) + { + if (crecp->flags & F_DS) + blockdata_free(crecp->addr.sig.keydata); + else + blockdata_free(crecp->addr.key.keydata); + } + else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG)) + blockdata_free(crecp->addr.ds.keydata); +} +#endif + static void cache_free(struct crec *crecp) { crecp->flags &= ~F_FORWARD; crecp->flags &= ~F_REVERSE; - crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ - + crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */ + if (cache_tail) cache_tail->next = crecp; else @@ -193,9 +221,9 @@ static void cache_free(struct crec *crecp) big_free = crecp->name.bname; crecp->flags &= ~F_BIGNAME; } + #ifdef HAVE_DNSSEC - else if (crecp->flags & (F_DNSKEY | F_DS)) - keydata_free(crecp->addr.key.keydata); + cache_blockdata_free(crecp); #endif } @@ -235,6 +263,16 @@ char *cache_get_name(struct crec *crecp) return crecp->name.sname; } +char *cache_get_cname_target(struct crec *crecp) +{ + if (crecp->addr.cname.uid != SRC_INTERFACE) + return cache_get_name(crecp->addr.cname.target.cache); + + return crecp->addr.cname.target.int_name->name; +} + + + struct crec *cache_enumerate(int init) { static int bucket; @@ -260,14 +298,14 @@ struct crec *cache_enumerate(int init) static int is_outdated_cname_pointer(struct crec *crecp) { - if (!(crecp->flags & F_CNAME)) + if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE) return 0; /* NB. record may be reused as DS or DNSKEY, where uid is overloaded for something completely different */ - if (crecp->addr.cname.cache && - (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && - crecp->addr.cname.uid == crecp->addr.cname.cache->uid) + if (crecp->addr.cname.target.cache && + (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && + crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid) return 0; return 1; @@ -304,27 +342,52 @@ static int cache_scan_free(char *name, struct all_addr if (flags & F_FORWARD) { for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next) - if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) - { - *up = crecp->hash_next; - if (!(crecp->flags & (F_HOSTS | F_DHCP))) - { - cache_unlink(crecp); - cache_free(crecp); - } - } - else if ((crecp->flags & F_FORWARD) && - ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) && - hostname_isequal(cache_get_name(crecp), name)) - { - if (crecp->flags & (F_HOSTS | F_DHCP)) - return 0; - *up = crecp->hash_next; - cache_unlink(crecp); - cache_free(crecp); - } - else + { + if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) + { + *up = crecp->hash_next; + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) + { + cache_unlink(crecp); + cache_free(crecp); + } + continue; + } + + if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) + { + /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ + if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || + (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) + { + if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) + return 0; + *up = crecp->hash_next; + cache_unlink(crecp); + cache_free(crecp); + continue; + } + +#ifdef HAVE_DNSSEC + /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also + type-covered sensitive for RRSIG */ + if ((flags & (F_DNSKEY | F_DS)) && + (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) && + crecp->uid == addr->addr.dnssec.class && + (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) || + crecp->addr.sig.type_covered == addr->addr.dnssec.type)) + { + if (crecp->flags & F_CONFIG) + return 0; + *up = crecp->hash_next; + cache_unlink(crecp); + cache_free(crecp); + continue; + } +#endif + } up = &crecp->hash_next; + } } else { @@ -341,13 +404,13 @@ static int cache_scan_free(char *name, struct all_addr if (is_expired(now, crecp)) { *up = crecp->hash_next; - if (!(crecp->flags & (F_HOSTS | F_DHCP))) + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) { cache_unlink(crecp); cache_free(crecp); } } - else if (!(crecp->flags & (F_HOSTS | F_DHCP)) && + else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && (flags & crecp->flags & F_REVERSE) && (flags & crecp->flags & (F_IPV4 | F_IPV6)) && memcmp(&crecp->addr.addr, addr, addrlen) == 0) @@ -394,19 +457,21 @@ struct crec *cache_insert(char *name, struct all_addr int freed_all = flags & F_REVERSE; int free_avail = 0; - if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) - ttl = daemon->max_cache_ttl; + /* Don't log DNSSEC records here, done elsewhere */ + if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) + { + log_query(flags | F_UPSTREAM, name, addr, NULL); + /* Don;t mess with TTL for DNSSEC records. */ + if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) + ttl = daemon->max_cache_ttl; + } - /* Don't log keys */ - if (flags & (F_IPV4 | F_IPV6)) - log_query(flags | F_UPSTREAM, name, addr, NULL); - /* if previous insertion failed give up now. */ if (insert_error) return NULL; - + /* First remove any expired entries and entries for the name/address we - are currently inserting. Fail is we attempt to delete a name from + are currently inserting. Fail if we attempt to delete a name from /etc/hosts or DHCP. */ if (!cache_scan_free(name, addr, now, flags)) { @@ -434,14 +499,32 @@ struct crec *cache_insert(char *name, struct all_addr insert. Once in this state, all inserts will probably fail. */ if (free_avail) { + static int warned = 0; + if (!warned) + { + my_syslog(LOG_ERR, _("Internal error in cache.")); + warned = 1; + } insert_error = 1; return NULL; } if (freed_all) { + struct all_addr free_addr = new->addr.addr;; + +#ifdef HAVE_DNSSEC + /* For DNSSEC records, addr holds class and type_covered for RRSIG */ + if (new->flags & (F_DS | F_DNSKEY)) + { + free_addr.addr.dnssec.class = new->uid; + if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) + free_addr.addr.dnssec.type = new->addr.sig.type_covered; + } +#endif + free_avail = 1; /* Must be free space now. */ - cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags); + cache_scan_free(cache_get_name(new), &free_addr, now, new->flags); cache_live_freed++; } else @@ -453,7 +536,7 @@ struct crec *cache_insert(char *name, struct all_addr } /* Check if we need to and can allocate extra memory for a long name. - If that fails, give up now. */ + If that fails, give up now, always succeed for DNSSEC records. */ if (name && (strlen(name) > SMALLDNAME-1)) { if (big_free) @@ -461,13 +544,13 @@ struct crec *cache_insert(char *name, struct all_addr big_name = big_free; big_free = big_free->next; } - else if (!bignames_left || + else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) || !(big_name = (union bigname *)whine_malloc(sizeof(union bigname)))) { insert_error = 1; return NULL; } - else + else if (bignames_left != 0) bignames_left--; } @@ -490,7 +573,14 @@ struct crec *cache_insert(char *name, struct all_addr *cache_get_name(new) = 0; if (addr) - new->addr.addr = *addr; + { +#ifdef HAVE_DNSSEC + if (flags & (F_DS | F_DNSKEY)) + new->uid = addr->addr.dnssec.class; + else +#endif + new->addr.addr = *addr; + } new->ttd = now + (time_t)ttl; new->next = new_chain; @@ -522,10 +612,13 @@ void cache_end_insert(void) new_chain = NULL; } -struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot) +struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) { struct crec *ans; + int no_rr = prot & F_NO_RR; + prot &= ~F_NO_RR; + if (crecp) /* iterating */ ans = crecp->next; else @@ -542,10 +635,13 @@ struct crec *cache_find_by_name(struct crec *crecp, ch if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp)) { if ((crecp->flags & F_FORWARD) && +#ifdef HAVE_DNSSEC + ((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) && +#endif (crecp->flags & prot) && hostname_isequal(cache_get_name(crecp), name)) { - if (crecp->flags & (F_HOSTS | F_DHCP)) + if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) { *chainp = crecp; chainp = &crecp->next; @@ -570,7 +666,7 @@ struct crec *cache_find_by_name(struct crec *crecp, ch } else { - if (!insert) + if (!insert && !no_rr) { insert = up; ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL); @@ -586,7 +682,7 @@ struct crec *cache_find_by_name(struct crec *crecp, ch { /* expired entry, free it */ *up = crecp->hash_next; - if (!(crecp->flags & (F_HOSTS | F_DHCP))) + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) { cache_unlink(crecp); cache_free(crecp); @@ -599,7 +695,10 @@ struct crec *cache_find_by_name(struct crec *crecp, ch if (ans && (ans->flags & F_FORWARD) && - (ans->flags & prot) && +#ifdef HAVE_DNSSEC + ((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) && +#endif + (ans->flags & prot) && hostname_isequal(cache_get_name(ans), name)) return ans; @@ -607,7 +706,7 @@ struct crec *cache_find_by_name(struct crec *crecp, ch } struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, - time_t now, unsigned short prot) + time_t now, unsigned int prot) { struct crec *ans; #ifdef HAVE_IPV6 @@ -636,7 +735,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, st if ((crecp->flags & prot) && memcmp(&crecp->addr.addr, addr, addrlen) == 0) { - if (crecp->flags & (F_HOSTS | F_DHCP)) + if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) { *chainp = crecp; chainp = &crecp->next; @@ -652,7 +751,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, st else { *up = crecp->hash_next; - if (!(crecp->flags & (F_HOSTS | F_DHCP))) + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) { cache_unlink(crecp); cache_free(crecp); @@ -680,17 +779,18 @@ static void add_hosts_cname(struct crec *target) if (hostname_isequal(cache_get_name(target), a->target) && (crec = whine_malloc(sizeof(struct crec)))) { - crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME; + crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME; crec->name.namep = a->alias; - crec->addr.cname.cache = target; + crec->addr.cname.target.cache = target; crec->addr.cname.uid = target->uid; + crec->uid = next_uid(); cache_hash(crec); add_hosts_cname(crec); /* handle chains */ } } static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, - int index, struct crec **rhash, int hashsz) + unsigned int index, struct crec **rhash, int hashsz) { struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6)); int i, nameexists = 0; @@ -794,7 +894,7 @@ static int gettok(FILE *f, char *token) } } -static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz) +static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz) { FILE *f = fopen(filename, "r"); char *token = daemon->namebuff, *domain_suffix = NULL; @@ -901,14 +1001,22 @@ void cache_reload(void) struct hostsfile *ah; struct host_record *hr; struct name_list *nl; + struct cname *a; + struct interface_name *intr; +#ifdef HAVE_DNSSEC + struct ds_config *ds; +#endif cache_inserted = cache_live_freed = 0; for (i=0; ihash_next; - if (cache->flags & F_HOSTS) + if (cache->flags & (F_HOSTS | F_CONFIG)) { *up = cache->hash_next; free(cache); @@ -927,6 +1035,37 @@ void cache_reload(void) up = &cache->hash_next; } + /* Add CNAMEs to interface_names to the cache */ + for (a = daemon->cnames; a; a = a->next) + for (intr = daemon->int_names; intr; intr = intr->next) + if (hostname_isequal(a->target, intr->name) && + ((cache = whine_malloc(sizeof(struct crec))))) + { + cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; + cache->name.namep = a->alias; + cache->addr.cname.target.int_name = intr; + cache->addr.cname.uid = SRC_INTERFACE; + cache->uid = next_uid(); + cache_hash(cache); + add_hosts_cname(cache); /* handle chains */ + } + +#ifdef HAVE_DNSSEC + for (ds = daemon->ds; ds; ds = ds->next) + if ((cache = whine_malloc(sizeof(struct crec))) && + (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen))) + { + cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP; + cache->name.namep = ds->name; + cache->addr.ds.keylen = ds->digestlen; + cache->addr.ds.algo = ds->algo; + cache->addr.ds.keytag = ds->keytag; + cache->addr.ds.digest = ds->digest_type; + cache->uid = ds->class; + cache_hash(cache); + } +#endif + /* borrow the packet buffer for a temporary by-address hash */ memset(daemon->packet, 0, daemon->packet_buff_sz); revhashsz = daemon->packet_buff_sz / sizeof(struct crec *); @@ -942,7 +1081,7 @@ void cache_reload(void) { cache->name.namep = nl->name; cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG; - add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz); + add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); } #ifdef HAVE_IPV6 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && @@ -950,7 +1089,7 @@ void cache_reload(void) { cache->name.namep = nl->name; cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG; - add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz); + add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); } #endif } @@ -963,7 +1102,7 @@ void cache_reload(void) } if (!option_bool(OPT_NO_HOSTS)) - total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz); + total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz); daemon->addn_hosts = expand_filelist(daemon->addn_hosts); for (ah = daemon->addn_hosts; ah; ah = ah->next) @@ -971,38 +1110,6 @@ void cache_reload(void) total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); } -char *get_domain(struct in_addr addr) -{ - struct cond_domain *c; - - for (c = daemon->cond_domain; c; c = c->next) - if (!c->is6 && - ntohl(addr.s_addr) >= ntohl(c->start.s_addr) && - ntohl(addr.s_addr) <= ntohl(c->end.s_addr)) - return c->domain; - - return daemon->domain_suffix; -} - - -#ifdef HAVE_IPV6 -char *get_domain6(struct in6_addr *addr) -{ - struct cond_domain *c; - - u64 addrpart = addr6part(addr); - - for (c = daemon->cond_domain; c; c = c->next) - if (c->is6 && - is_same_net6(addr, &c->start6, 64) && - addrpart >= addr6part(&c->start6) && - addrpart <= addr6part(&c->end6)) - return c->domain; - - return daemon->domain_suffix; -} -#endif - #ifdef HAVE_DHCP struct in_addr a_record_from_hosts(char *name, time_t now) { @@ -1051,14 +1158,15 @@ static void add_dhcp_cname(struct crec *target, time_t if (aliasc) { - aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME; + aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG; if (ttd == 0) aliasc->flags |= F_IMMORTAL; else aliasc->ttd = ttd; aliasc->name.namep = a->alias; - aliasc->addr.cname.cache = target; + aliasc->addr.cname.target.cache = target; aliasc->addr.cname.uid = target->uid; + aliasc->uid = next_uid(); cache_hash(aliasc); add_dhcp_cname(aliasc, ttd); } @@ -1086,7 +1194,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME))) { /* check all addresses associated with name */ - if (crec->flags & F_HOSTS) + if (crec->flags & (F_HOSTS | F_CONFIG)) { if (crec->flags & F_CNAME) my_syslog(MS_DHCP | LOG_WARNING, @@ -1146,7 +1254,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, crec->ttd = ttd; crec->addr.addr = *host_address; crec->name.namep = host_name; - crec->uid = uid++; + crec->uid = next_uid(); cache_hash(crec); add_dhcp_cname(crec, ttd); @@ -1154,16 +1262,118 @@ void cache_add_dhcp_entry(char *host_name, int prot, } #endif +int cache_make_stat(struct txt_record *t) +{ + static char *buff = NULL; + static int bufflen = 60; + int len; + struct server *serv, *serv1; + char *p; + if (!buff && !(buff = whine_malloc(60))) + return 0; + + p = buff; + + switch (t->stat) + { + case TXT_STAT_CACHESIZE: + sprintf(buff+1, "%d", daemon->cachesize); + break; + + case TXT_STAT_INSERTS: + sprintf(buff+1, "%d", cache_inserted); + break; + + case TXT_STAT_EVICTIONS: + sprintf(buff+1, "%d", cache_live_freed); + break; + + case TXT_STAT_MISSES: + sprintf(buff+1, "%u", daemon->queries_forwarded); + break; + + case TXT_STAT_HITS: + sprintf(buff+1, "%u", daemon->local_answer); + break; + +#ifdef HAVE_AUTH + case TXT_STAT_AUTH: + sprintf(buff+1, "%u", daemon->auth_answer); + break; +#endif + + case TXT_STAT_SERVERS: + /* sum counts from different records for same server */ + for (serv = daemon->servers; serv; serv = serv->next) + serv->flags &= ~SERV_COUNTED; + + for (serv = daemon->servers; serv; serv = serv->next) + if (!(serv->flags & + (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND))) + { + char *new, *lenp; + int port, newlen, bytes_avail, bytes_needed; + unsigned int queries = 0, failed_queries = 0; + for (serv1 = serv; serv1; serv1 = serv1->next) + if (!(serv1->flags & + (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && + sockaddr_isequal(&serv->addr, &serv1->addr)) + { + serv1->flags |= SERV_COUNTED; + queries += serv1->queries; + failed_queries += serv1->failed_queries; + } + port = prettyprint_addr(&serv->addr, daemon->addrbuff); + lenp = p++; /* length */ + bytes_avail = (p - buff) + bufflen; + bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries); + if (bytes_needed >= bytes_avail) + { + /* expand buffer if necessary */ + newlen = bytes_needed + 1 + bufflen - bytes_avail; + if (!(new = whine_malloc(newlen))) + return 0; + memcpy(new, buff, bufflen); + free(buff); + p = new + (p - buff); + lenp = p - 1; + buff = new; + bufflen = newlen; + bytes_avail = (p - buff) + bufflen; + bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries); + } + *lenp = bytes_needed; + p += bytes_needed; + } + t->txt = (unsigned char *)buff; + t->len = p - buff; + return 1; + } + + len = strlen(buff+1); + t->txt = (unsigned char *)buff; + t->len = len + 1; + *buff = len; + return 1; +} + void dump_cache(time_t now) { struct server *serv, *serv1; + char *t = ""; my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now); my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."), daemon->cachesize, cache_live_freed, cache_inserted); my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), daemon->queries_forwarded, daemon->local_answer); +#ifdef HAVE_AUTH + my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer); +#endif +#ifdef HAVE_DNSSEC + blockdata_report(); +#endif /* sum counts from different records for same server */ for (serv = daemon->servers; serv; serv = serv->next) @@ -1192,35 +1402,34 @@ void dump_cache(time_t now) { struct crec *cache ; int i; - my_syslog(LOG_INFO, "Host Address Flags Expires"); + my_syslog(LOG_INFO, "Host Address Flags Expires"); for (i=0; ihash_next) { - char *a, *p = daemon->namebuff; - p += sprintf(p, "%-40.40s ", cache_get_name(cache)); - if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD)) - a = ""; - else if (cache->flags & F_CNAME) - { - a = ""; - if (!is_outdated_cname_pointer(cache)) - a = cache_get_name(cache->addr.cname.cache); - } + char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); + *a = 0; + if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) + n = ""; + p += sprintf(p, "%-40.40s ", n); + if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) + a = cache_get_cname_target(cache); #ifdef HAVE_DNSSEC - else if (cache->flags & F_DNSKEY) - { - a = daemon->addrbuff; - sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid); - } else if (cache->flags & F_DS) { - a = daemon->addrbuff; - sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid, - cache->addr.key.algo, cache->addr.key.digest, cache->uid); + if (cache->flags & F_DNSKEY) + /* RRSIG */ + sprintf(a, "%5u %3u %s", cache->addr.sig.keytag, + cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered)); + else if (!(cache->flags & F_NEG)) + sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, + cache->addr.ds.algo, cache->addr.ds.digest); } + else if (cache->flags & F_DNSKEY) + sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, + cache->addr.key.algo, cache->addr.key.flags); #endif - else + else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) { a = daemon->addrbuff; if (cache->flags & F_IPV4) @@ -1231,12 +1440,21 @@ void dump_cache(time_t now) #endif } - p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a, - cache->flags & F_IPV4 ? "4" : "", - cache->flags & F_IPV6 ? "6" : "", - cache->flags & F_DNSKEY ? "K" : "", - cache->flags & F_DS ? "S" : "", - cache->flags & F_CNAME ? "C" : "", + if (cache->flags & F_IPV4) + t = "4"; + else if (cache->flags & F_IPV6) + t = "6"; + else if (cache->flags & F_CNAME) + t = "C"; +#ifdef HAVE_DNSSEC + else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) + t = "G"; /* DNSKEY and DS set -> RRISG */ + else if (cache->flags & F_DS) + t = "S"; + else if (cache->flags & F_DNSKEY) + t = "K"; +#endif + p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t, cache->flags & F_FORWARD ? "F" : " ", cache->flags & F_REVERSE ? "R" : " ", cache->flags & F_IMMORTAL ? "I" : " ", @@ -1257,11 +1475,13 @@ void dump_cache(time_t now) } } -char *record_source(int index) +char *record_source(unsigned int index) { struct hostsfile *ah; - if (index == 0) + if (index == SRC_CONFIG) + return "config"; + else if (index == SRC_HOSTS) return HOSTSFILE; for (ah = daemon->addn_hosts; ah; ah = ah->next) @@ -1271,14 +1491,45 @@ char *record_source(int index) return ""; } -void querystr(char *desc, char *str, unsigned short type) +char *querystr(char *desc, unsigned short type) { unsigned int i; - - sprintf(str, "%s[type=%d]", desc, type); + int len = 10; /* strlen("type=xxxxx") */ + const char *types = NULL; + static char *buff = NULL; + static int bufflen = 0; + for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) if (typestr[i].type == type) - sprintf(str,"%s[%s]", desc, typestr[i].name); + { + types = typestr[i].name; + len = strlen(types); + break; + } + + len += 3; /* braces, terminator */ + len += strlen(desc); + + if (!buff || bufflen < len) + { + if (buff) + free(buff); + else if (len < 20) + len = 20; + + buff = whine_malloc(len); + bufflen = len; + } + + if (buff) + { + if (types) + sprintf(buff, "%s[%s]", desc, types); + else + sprintf(buff, "%s[type=%d]", desc, type); + } + + return buff ? buff : ""; } void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) @@ -1291,13 +1542,20 @@ void log_query(unsigned int flags, char *name, struct if (addr) { + if (flags & F_KEYTAG) + sprintf(daemon->addrbuff, arg, addr->addr.keytag); + else + { #ifdef HAVE_IPV6 - inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, - addr, daemon->addrbuff, ADDRSTRLEN); + inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, + addr, daemon->addrbuff, ADDRSTRLEN); #else - strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN); + strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN); #endif + } } + else + dest = arg; if (flags & F_REVERSE) { @@ -1308,14 +1566,7 @@ void log_query(unsigned int flags, char *name, struct if (flags & F_NEG) { if (flags & F_NXDOMAIN) - { - if (flags & F_IPV4) - dest = "NXDOMAIN-IPv4"; - else if (flags & F_IPV6) - dest = "NXDOMAIN-IPv6"; - else - dest = "NXDOMAIN"; - } + dest = "NXDOMAIN"; else { if (flags & F_IPV4) @@ -1339,6 +1590,8 @@ void log_query(unsigned int flags, char *name, struct source = arg; else if (flags & F_UPSTREAM) source = "reply"; + else if (flags & F_SECSTAT) + source = "validation"; else if (flags & F_AUTH) source = "auth"; else if (flags & F_SERVER) @@ -1351,6 +1604,18 @@ void log_query(unsigned int flags, char *name, struct source = arg; verb = "from"; } + else if (flags & F_DNSSEC) + { + source = arg; + verb = "to"; + } + else if (flags & F_IPSET) + { + source = "ipset add"; + dest = name; + name = arg; + verb = daemon->addrbuff; + } else source = "cached"; @@ -1360,50 +1625,4 @@ void log_query(unsigned int flags, char *name, struct my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); } -#ifdef HAVE_DNSSEC -struct keydata *keydata_alloc(char *data, size_t len) -{ - struct keydata *block, *ret = NULL; - struct keydata **prev = &ret; - while (len > 0) - { - if (keyblock_free) - { - block = keyblock_free; - keyblock_free = block->next; - } - else - block = whine_malloc(sizeof(struct keydata)); - - if (!block) - { - /* failed to alloc, free partial chain */ - keydata_free(ret); - return NULL; - } - - memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len); - data += KEYBLOCK_LEN; - len -= KEYBLOCK_LEN; - *prev = block; - prev = &block->next; - block->next = NULL; - } - - return ret; -} - -void keydata_free(struct keydata *blocks) -{ - struct keydata *tmp; - - if (blocks) - { - for (tmp = blocks; tmp->next; tmp = tmp->next); - tmp->next = keyblock_free; - keyblock_free = blocks; - } -} -#endif - - +