version 1.1.1.1, 2013/07/29 19:37:40
|
version 1.1.1.3, 2016/11/02 09:57:01
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
Line 24 static struct crec *new_chain = NULL;
|
Line 24 static struct crec *new_chain = NULL;
|
static int cache_inserted = 0, cache_live_freed = 0, insert_error; |
static int cache_inserted = 0, cache_live_freed = 0, insert_error; |
static union bigname *big_free = NULL; |
static union bigname *big_free = NULL; |
static int bignames_left, hash_size; |
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. */ |
/* type->string mapping: this is also used by the name-hash function as a mixing table. */ |
static const struct { |
static const struct { |
Line 56 static const struct {
|
Line 52 static const struct {
|
{ 38, "A6" }, |
{ 38, "A6" }, |
{ 39, "DNAME" }, |
{ 39, "DNAME" }, |
{ 41, "OPT" }, |
{ 41, "OPT" }, |
|
{ 43, "DS" }, |
|
{ 46, "RRSIG" }, |
|
{ 47, "NSEC" }, |
{ 48, "DNSKEY" }, |
{ 48, "DNSKEY" }, |
|
{ 50, "NSEC3" }, |
{ 249, "TKEY" }, |
{ 249, "TKEY" }, |
{ 250, "TSIG" }, |
{ 250, "TSIG" }, |
{ 251, "IXFR" }, |
{ 251, "IXFR" }, |
Line 72 static void cache_link(struct crec *crecp);
|
Line 72 static void cache_link(struct crec *crecp);
|
static void rehash(int size); |
static void rehash(int size); |
static void cache_hash(struct crec *crecp); |
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) |
void cache_init(void) |
{ |
{ |
struct crec *crecp; |
struct crec *crecp; |
int i; |
int i; |
| |
bignames_left = daemon->cachesize/10; |
bignames_left = daemon->cachesize/10; |
|
|
if (daemon->cachesize > 0) |
if (daemon->cachesize > 0) |
Line 87 void cache_init(void)
|
Line 100 void cache_init(void)
|
{ |
{ |
cache_link(crecp); |
cache_link(crecp); |
crecp->flags = 0; |
crecp->flags = 0; |
crecp->uid = uid++; | crecp->uid = next_uid(); |
} |
} |
} |
} |
|
|
Line 171 static void cache_hash(struct crec *crecp)
|
Line 184 static void cache_hash(struct crec *crecp)
|
crecp->hash_next = *up; |
crecp->hash_next = *up; |
*up = crecp; |
*up = crecp; |
} |
} |
| |
| #ifdef HAVE_DNSSEC |
| static void cache_blockdata_free(struct crec *crecp) |
| { |
| if (crecp->flags & F_DNSKEY) |
| 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) |
static void cache_free(struct crec *crecp) |
{ |
{ |
crecp->flags &= ~F_FORWARD; |
crecp->flags &= ~F_FORWARD; |
crecp->flags &= ~F_REVERSE; |
crecp->flags &= ~F_REVERSE; |
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ | crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */ |
| |
if (cache_tail) |
if (cache_tail) |
cache_tail->next = crecp; |
cache_tail->next = crecp; |
else |
else |
Line 193 static void cache_free(struct crec *crecp)
|
Line 216 static void cache_free(struct crec *crecp)
|
big_free = crecp->name.bname; |
big_free = crecp->name.bname; |
crecp->flags &= ~F_BIGNAME; |
crecp->flags &= ~F_BIGNAME; |
} |
} |
|
|
#ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
else if (crecp->flags & (F_DNSKEY | F_DS)) | cache_blockdata_free(crecp); |
keydata_free(crecp->addr.key.keydata); | |
#endif |
#endif |
} |
} |
|
|
Line 235 char *cache_get_name(struct crec *crecp)
|
Line 258 char *cache_get_name(struct crec *crecp)
|
return crecp->name.sname; |
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) |
struct crec *cache_enumerate(int init) |
{ |
{ |
static int bucket; |
static int bucket; |
Line 260 struct crec *cache_enumerate(int init)
|
Line 293 struct crec *cache_enumerate(int init)
|
|
|
static int is_outdated_cname_pointer(struct crec *crecp) |
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; |
return 0; |
|
|
/* NB. record may be reused as DS or DNSKEY, where uid is |
/* NB. record may be reused as DS or DNSKEY, where uid is |
overloaded for something completely different */ |
overloaded for something completely different */ |
if (crecp->addr.cname.cache && | if (crecp->addr.cname.target.cache && |
(crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && | (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && |
crecp->addr.cname.uid == crecp->addr.cname.cache->uid) | crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid) |
return 0; |
return 0; |
|
|
return 1; |
return 1; |
Line 284 static int is_expired(time_t now, struct crec *crecp)
|
Line 317 static int is_expired(time_t now, struct crec *crecp)
|
return 1; |
return 1; |
} |
} |
|
|
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) | static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) |
{ |
{ |
/* Scan and remove old entries. |
/* Scan and remove old entries. |
If (flags & F_FORWARD) then remove any forward entries for name and any expired |
If (flags & F_FORWARD) then remove any forward entries for name and any expired |
Line 293 static int cache_scan_free(char *name, struct all_addr
|
Line 326 static int cache_scan_free(char *name, struct all_addr
|
entries in the whole cache. |
entries in the whole cache. |
If (flags == 0) remove any expired entries in the whole cache. |
If (flags == 0) remove any expired entries in the whole cache. |
|
|
In the flags & F_FORWARD case, the return code is valid, and returns zero if the | In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer |
name exists in the cache as a HOSTS or DHCP entry (these are never deleted) | to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted) |
|
|
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal> |
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal> |
so that when we hit an entry which isn't reverse and is immortal, we're done. */ |
so that when we hit an entry which isn't reverse and is immortal, we're done. */ |
Line 304 static int cache_scan_free(char *name, struct all_addr
|
Line 337 static int cache_scan_free(char *name, struct all_addr
|
if (flags & F_FORWARD) |
if (flags & F_FORWARD) |
{ |
{ |
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next) |
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next) |
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) | { |
{ | if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) |
*up = crecp->hash_next; | { |
if (!(crecp->flags & (F_HOSTS | F_DHCP))) | *up = crecp->hash_next; |
{ | if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) |
cache_unlink(crecp); | { |
cache_free(crecp); | cache_unlink(crecp); |
} | cache_free(crecp); |
} | } |
else if ((crecp->flags & F_FORWARD) && | continue; |
((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) && | } |
hostname_isequal(cache_get_name(crecp), name)) | |
{ | if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) |
if (crecp->flags & (F_HOSTS | F_DHCP)) | { |
return 0; | /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ |
*up = crecp->hash_next; | if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || |
cache_unlink(crecp); | (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) |
cache_free(crecp); | { |
} | if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
else | return crecp; |
| *up = crecp->hash_next; |
| cache_unlink(crecp); |
| cache_free(crecp); |
| continue; |
| } |
| |
| #ifdef HAVE_DNSSEC |
| /* Deletion has to be class-sensitive for DS and DNSKEY */ |
| if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class) |
| { |
| if (crecp->flags & F_CONFIG) |
| return crecp; |
| *up = crecp->hash_next; |
| cache_unlink(crecp); |
| cache_free(crecp); |
| continue; |
| } |
| #endif |
| } |
up = &crecp->hash_next; |
up = &crecp->hash_next; |
|
} |
} |
} |
else |
else |
{ |
{ |
Line 341 static int cache_scan_free(char *name, struct all_addr
|
Line 394 static int cache_scan_free(char *name, struct all_addr
|
if (is_expired(now, crecp)) |
if (is_expired(now, crecp)) |
{ |
{ |
*up = crecp->hash_next; |
*up = crecp->hash_next; |
if (!(crecp->flags & (F_HOSTS | F_DHCP))) | if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) |
{ |
{ |
cache_unlink(crecp); |
cache_unlink(crecp); |
cache_free(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_REVERSE) && |
(flags & crecp->flags & (F_IPV4 | F_IPV6)) && |
(flags & crecp->flags & (F_IPV4 | F_IPV6)) && |
memcmp(&crecp->addr.addr, addr, addrlen) == 0) |
memcmp(&crecp->addr.addr, addr, addrlen) == 0) |
Line 360 static int cache_scan_free(char *name, struct all_addr
|
Line 413 static int cache_scan_free(char *name, struct all_addr
|
up = &crecp->hash_next; |
up = &crecp->hash_next; |
} |
} |
|
|
return 1; | return NULL; |
} |
} |
|
|
/* Note: The normal calling sequence is |
/* Note: The normal calling sequence is |
Line 394 struct crec *cache_insert(char *name, struct all_addr
|
Line 447 struct crec *cache_insert(char *name, struct all_addr
|
int freed_all = flags & F_REVERSE; |
int freed_all = flags & F_REVERSE; |
int free_avail = 0; |
int free_avail = 0; |
|
|
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) | /* Don't log DNSSEC records here, done elsewhere */ |
ttl = daemon->max_cache_ttl; | 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; |
| if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |
| ttl = daemon->min_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 previous insertion failed give up now. */ |
if (insert_error) |
if (insert_error) |
return NULL; |
return NULL; |
| |
/* First remove any expired entries and entries for the name/address we |
/* 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. */ |
/etc/hosts or DHCP. */ | if ((new = cache_scan_free(name, addr, now, flags))) |
if (!cache_scan_free(name, addr, now, flags)) | |
{ |
{ |
|
/* We're trying to insert a record over one from |
|
/etc/hosts or DHCP, or other config. If the |
|
existing record is for an A or AAAA and |
|
the record we're trying to insert is the same, |
|
just drop the insert, but don't error the whole process. */ |
|
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr) |
|
{ |
|
if ((flags & F_IPV4) && (new->flags & F_IPV4) && |
|
new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr) |
|
return new; |
|
#ifdef HAVE_IPV6 |
|
else if ((flags & F_IPV6) && (new->flags & F_IPV6) && |
|
IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6)) |
|
return new; |
|
#endif |
|
} |
|
|
insert_error = 1; |
insert_error = 1; |
return NULL; |
return NULL; |
} |
} |
Line 434 struct crec *cache_insert(char *name, struct all_addr
|
Line 507 struct crec *cache_insert(char *name, struct all_addr
|
insert. Once in this state, all inserts will probably fail. */ |
insert. Once in this state, all inserts will probably fail. */ |
if (free_avail) |
if (free_avail) |
{ |
{ |
|
static int warned = 0; |
|
if (!warned) |
|
{ |
|
my_syslog(LOG_ERR, _("Internal error in cache.")); |
|
warned = 1; |
|
} |
insert_error = 1; |
insert_error = 1; |
return NULL; |
return NULL; |
} |
} |
|
|
if (freed_all) |
if (freed_all) |
{ |
{ |
|
struct all_addr free_addr = new->addr.addr;; |
|
|
|
#ifdef HAVE_DNSSEC |
|
/* For DNSSEC records, addr holds class. */ |
|
if (new->flags & (F_DS | F_DNSKEY)) |
|
free_addr.addr.dnssec.class = new->uid; |
|
#endif |
|
|
free_avail = 1; /* Must be free space now. */ |
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++; |
cache_live_freed++; |
} |
} |
else |
else |
Line 453 struct crec *cache_insert(char *name, struct all_addr
|
Line 540 struct crec *cache_insert(char *name, struct all_addr
|
} |
} |
|
|
/* Check if we need to and can allocate extra memory for a long name. |
/* 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 (name && (strlen(name) > SMALLDNAME-1)) |
{ |
{ |
if (big_free) |
if (big_free) |
Line 461 struct crec *cache_insert(char *name, struct all_addr
|
Line 548 struct crec *cache_insert(char *name, struct all_addr
|
big_name = big_free; |
big_name = big_free; |
big_free = big_free->next; |
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)))) |
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname)))) |
{ |
{ |
insert_error = 1; |
insert_error = 1; |
return NULL; |
return NULL; |
} |
} |
else | else if (bignames_left != 0) |
bignames_left--; |
bignames_left--; |
|
|
} |
} |
Line 490 struct crec *cache_insert(char *name, struct all_addr
|
Line 577 struct crec *cache_insert(char *name, struct all_addr
|
*cache_get_name(new) = 0; |
*cache_get_name(new) = 0; |
|
|
if (addr) |
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->ttd = now + (time_t)ttl; |
new->next = new_chain; |
new->next = new_chain; |
Line 522 void cache_end_insert(void)
|
Line 616 void cache_end_insert(void)
|
new_chain = NULL; |
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; |
struct crec *ans; |
|
int no_rr = prot & F_NO_RR; |
|
|
|
prot &= ~F_NO_RR; |
|
|
if (crecp) /* iterating */ |
if (crecp) /* iterating */ |
ans = crecp->next; |
ans = crecp->next; |
else |
else |
Line 545 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 642 struct crec *cache_find_by_name(struct crec *crecp, ch
|
(crecp->flags & prot) && |
(crecp->flags & prot) && |
hostname_isequal(cache_get_name(crecp), name)) |
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; |
chainp = &crecp->next; |
chainp = &crecp->next; |
Line 570 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 667 struct crec *cache_find_by_name(struct crec *crecp, ch
|
} |
} |
else |
else |
{ |
{ |
if (!insert) | if (!insert && !no_rr) |
{ |
{ |
insert = up; |
insert = up; |
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL); |
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL); |
Line 586 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 683 struct crec *cache_find_by_name(struct crec *crecp, ch
|
{ |
{ |
/* expired entry, free it */ |
/* expired entry, free it */ |
*up = crecp->hash_next; |
*up = crecp->hash_next; |
if (!(crecp->flags & (F_HOSTS | F_DHCP))) | if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) |
{ |
{ |
cache_unlink(crecp); |
cache_unlink(crecp); |
cache_free(crecp); |
cache_free(crecp); |
Line 599 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 696 struct crec *cache_find_by_name(struct crec *crecp, ch
|
|
|
if (ans && |
if (ans && |
(ans->flags & F_FORWARD) && |
(ans->flags & F_FORWARD) && |
(ans->flags & prot) && | (ans->flags & prot) && |
hostname_isequal(cache_get_name(ans), name)) |
hostname_isequal(cache_get_name(ans), name)) |
return ans; |
return ans; |
|
|
Line 607 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 704 struct crec *cache_find_by_name(struct crec *crecp, ch
|
} |
} |
|
|
struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, |
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; |
struct crec *ans; |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
Line 636 struct crec *cache_find_by_addr(struct crec *crecp, st
|
Line 733 struct crec *cache_find_by_addr(struct crec *crecp, st
|
if ((crecp->flags & prot) && |
if ((crecp->flags & prot) && |
memcmp(&crecp->addr.addr, addr, addrlen) == 0) |
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; |
chainp = &crecp->next; |
chainp = &crecp->next; |
Line 652 struct crec *cache_find_by_addr(struct crec *crecp, st
|
Line 749 struct crec *cache_find_by_addr(struct crec *crecp, st
|
else |
else |
{ |
{ |
*up = crecp->hash_next; |
*up = crecp->hash_next; |
if (!(crecp->flags & (F_HOSTS | F_DHCP))) | if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))) |
{ |
{ |
cache_unlink(crecp); |
cache_unlink(crecp); |
cache_free(crecp); |
cache_free(crecp); |
Line 680 static void add_hosts_cname(struct crec *target)
|
Line 777 static void add_hosts_cname(struct crec *target)
|
if (hostname_isequal(cache_get_name(target), a->target) && |
if (hostname_isequal(cache_get_name(target), a->target) && |
(crec = whine_malloc(sizeof(struct crec)))) |
(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->ttd = a->ttl; |
crec->name.namep = a->alias; |
crec->name.namep = a->alias; |
crec->addr.cname.cache = target; | crec->addr.cname.target.cache = target; |
crec->addr.cname.uid = target->uid; |
crec->addr.cname.uid = target->uid; |
|
crec->uid = next_uid(); |
cache_hash(crec); |
cache_hash(crec); |
add_hosts_cname(crec); /* handle chains */ |
add_hosts_cname(crec); /* handle chains */ |
} |
} |
} |
} |
|
|
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, |
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)); |
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6)); |
int i, nameexists = 0; |
int i, nameexists = 0; |
Line 717 static void add_hosts_entry(struct crec *cache, struct
|
Line 816 static void add_hosts_entry(struct crec *cache, struct
|
Only insert each unique address once into this hashing structure. |
Only insert each unique address once into this hashing structure. |
|
|
This complexity avoids O(n^2) divergent CPU use whilst reading |
This complexity avoids O(n^2) divergent CPU use whilst reading |
large (10000 entry) hosts files. */ | large (10000 entry) hosts files. |
| |
| Note that we only do this process when bulk-reading hosts files, |
| for incremental reads, rhash is NULL, and we use cache lookups |
| instead. |
| */ |
|
|
/* hash address */ | if (rhash) |
for (j = 0, i = 0; i < addrlen; i++) | |
j = (j*2 +((unsigned char *)addr)[i]) % hashsz; | |
| |
for (lookup = rhash[j]; lookup; lookup = lookup->next) | |
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) && | |
memcmp(&lookup->addr.addr, addr, addrlen) == 0) | |
{ | |
cache->flags &= ~F_REVERSE; | |
break; | |
} | |
| |
/* maintain address hash chain, insert new unique address */ | |
if (!lookup) | |
{ |
{ |
cache->next = rhash[j]; | /* hash address */ |
rhash[j] = cache; | for (j = 0, i = 0; i < addrlen; i++) |
| j = (j*2 +((unsigned char *)addr)[i]) % hashsz; |
| |
| for (lookup = rhash[j]; lookup; lookup = lookup->next) |
| if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) && |
| memcmp(&lookup->addr.addr, addr, addrlen) == 0) |
| { |
| cache->flags &= ~F_REVERSE; |
| break; |
| } |
| |
| /* maintain address hash chain, insert new unique address */ |
| if (!lookup) |
| { |
| cache->next = rhash[j]; |
| rhash[j] = cache; |
| } |
} |
} |
| else |
| { |
| /* incremental read, lookup in cache */ |
| lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6)); |
| if (lookup && lookup->flags & F_HOSTS) |
| cache->flags &= ~F_REVERSE; |
| } |
| |
cache->uid = index; |
cache->uid = index; |
memcpy(&cache->addr.addr, addr, addrlen); |
memcpy(&cache->addr.addr, addr, addrlen); |
cache_hash(cache); |
cache_hash(cache); |
Line 794 static int gettok(FILE *f, char *token)
|
Line 908 static int gettok(FILE *f, char *token)
|
} |
} |
} |
} |
|
|
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz) | int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz) |
{ |
{ |
FILE *f = fopen(filename, "r"); |
FILE *f = fopen(filename, "r"); |
char *token = daemon->namebuff, *domain_suffix = NULL; |
char *token = daemon->namebuff, *domain_suffix = NULL; |
Line 806 static int read_hostsfile(char *filename, int index, i
|
Line 920 static int read_hostsfile(char *filename, int index, i
|
if (!f) |
if (!f) |
{ |
{ |
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno)); |
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno)); |
return 0; | return cache_size; |
} |
} |
|
|
eatspace(f); |
eatspace(f); |
Line 840 static int read_hostsfile(char *filename, int index, i
|
Line 954 static int read_hostsfile(char *filename, int index, i
|
addr_count++; |
addr_count++; |
|
|
/* rehash every 1000 names. */ |
/* rehash every 1000 names. */ |
if ((name_count - cache_size) > 1000) | if (rhash && ((name_count - cache_size) > 1000)) |
{ |
{ |
rehash(name_count); |
rehash(name_count); |
cache_size = name_count; |
cache_size = name_count; |
Line 868 static int read_hostsfile(char *filename, int index, i
|
Line 982 static int read_hostsfile(char *filename, int index, i
|
strcat(cache->name.sname, "."); |
strcat(cache->name.sname, "."); |
strcat(cache->name.sname, domain_suffix); |
strcat(cache->name.sname, domain_suffix); |
cache->flags = flags; |
cache->flags = flags; |
|
cache->ttd = daemon->local_ttl; |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
name_count++; |
name_count++; |
} |
} |
Line 875 static int read_hostsfile(char *filename, int index, i
|
Line 990 static int read_hostsfile(char *filename, int index, i
|
{ |
{ |
strcpy(cache->name.sname, canon); |
strcpy(cache->name.sname, canon); |
cache->flags = flags; |
cache->flags = flags; |
|
cache->ttd = daemon->local_ttl; |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
name_count++; |
name_count++; |
} |
} |
Line 887 static int read_hostsfile(char *filename, int index, i
|
Line 1003 static int read_hostsfile(char *filename, int index, i
|
} |
} |
|
|
fclose(f); |
fclose(f); |
rehash(name_count); |
|
|
|
|
if (rhash) |
|
rehash(name_count); |
|
|
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count); |
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count); |
|
|
return name_count; |
return name_count; |
Line 901 void cache_reload(void)
|
Line 1019 void cache_reload(void)
|
struct hostsfile *ah; |
struct hostsfile *ah; |
struct host_record *hr; |
struct host_record *hr; |
struct name_list *nl; |
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; |
cache_inserted = cache_live_freed = 0; |
|
|
for (i=0; i<hash_size; i++) |
for (i=0; i<hash_size; i++) |
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp) |
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp) |
{ |
{ |
|
#ifdef HAVE_DNSSEC |
|
cache_blockdata_free(cache); |
|
#endif |
tmp = cache->hash_next; |
tmp = cache->hash_next; |
if (cache->flags & F_HOSTS) | if (cache->flags & (F_HOSTS | F_CONFIG)) |
{ |
{ |
*up = cache->hash_next; |
*up = cache->hash_next; |
free(cache); |
free(cache); |
Line 927 void cache_reload(void)
|
Line 1053 void cache_reload(void)
|
up = &cache->hash_next; |
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->ttd = a->ttl; |
|
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->ttd = daemon->local_ttl; |
|
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 */ |
/* borrow the packet buffer for a temporary by-address hash */ |
memset(daemon->packet, 0, daemon->packet_buff_sz); |
memset(daemon->packet, 0, daemon->packet_buff_sz); |
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *); |
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *); |
Line 941 void cache_reload(void)
|
Line 1100 void cache_reload(void)
|
(cache = whine_malloc(sizeof(struct crec)))) |
(cache = whine_malloc(sizeof(struct crec)))) |
{ |
{ |
cache->name.namep = nl->name; |
cache->name.namep = nl->name; |
|
cache->ttd = hr->ttl; |
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG; |
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 |
#ifdef HAVE_IPV6 |
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && |
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && |
(cache = whine_malloc(sizeof(struct crec)))) |
(cache = whine_malloc(sizeof(struct crec)))) |
{ |
{ |
cache->name.namep = nl->name; |
cache->name.namep = nl->name; |
|
cache->ttd = hr->ttl; |
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG; |
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 |
#endif |
} |
} |
Line 959 void cache_reload(void)
|
Line 1120 void cache_reload(void)
|
{ |
{ |
if (daemon->cachesize > 0) |
if (daemon->cachesize > 0) |
my_syslog(LOG_INFO, _("cleared cache")); |
my_syslog(LOG_INFO, _("cleared cache")); |
return; |
|
} |
} |
| else |
if (!option_bool(OPT_NO_HOSTS)) | { |
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz); | if (!option_bool(OPT_NO_HOSTS)) |
| 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) | daemon->addn_hosts = expand_filelist(daemon->addn_hosts); |
if (!(ah->flags & AH_INACTIVE)) | for (ah = daemon->addn_hosts; ah; ah = ah->next) |
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); | if (!(ah->flags & AH_INACTIVE)) |
} | total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); |
| } |
|
|
char *get_domain(struct in_addr addr) | #ifdef HAVE_INOTIFY |
{ | set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz); |
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 |
#endif |
|
|
|
} |
|
|
#ifdef HAVE_DHCP |
#ifdef HAVE_DHCP |
struct in_addr a_record_from_hosts(char *name, time_t now) |
struct in_addr a_record_from_hosts(char *name, time_t now) |
Line 1051 static void add_dhcp_cname(struct crec *target, time_t
|
Line 1186 static void add_dhcp_cname(struct crec *target, time_t
|
|
|
if (aliasc) |
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) |
if (ttd == 0) |
aliasc->flags |= F_IMMORTAL; |
aliasc->flags |= F_IMMORTAL; |
else |
else |
aliasc->ttd = ttd; |
aliasc->ttd = ttd; |
aliasc->name.namep = a->alias; |
aliasc->name.namep = a->alias; |
aliasc->addr.cname.cache = target; | aliasc->addr.cname.target.cache = target; |
aliasc->addr.cname.uid = target->uid; |
aliasc->addr.cname.uid = target->uid; |
|
aliasc->uid = next_uid(); |
cache_hash(aliasc); |
cache_hash(aliasc); |
add_dhcp_cname(aliasc, ttd); |
add_dhcp_cname(aliasc, ttd); |
} |
} |
Line 1086 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1222 void cache_add_dhcp_entry(char *host_name, int prot,
|
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME))) |
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME))) |
{ |
{ |
/* check all addresses associated with name */ |
/* check all addresses associated with name */ |
if (crec->flags & F_HOSTS) | if (crec->flags & (F_HOSTS | F_CONFIG)) |
{ |
{ |
if (crec->flags & F_CNAME) |
if (crec->flags & F_CNAME) |
my_syslog(MS_DHCP | LOG_WARNING, |
my_syslog(MS_DHCP | LOG_WARNING, |
Line 1146 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1282 void cache_add_dhcp_entry(char *host_name, int prot,
|
crec->ttd = ttd; |
crec->ttd = ttd; |
crec->addr.addr = *host_address; |
crec->addr.addr = *host_address; |
crec->name.namep = host_name; |
crec->name.namep = host_name; |
crec->uid = uid++; | crec->uid = next_uid(); |
cache_hash(crec); |
cache_hash(crec); |
|
|
add_dhcp_cname(crec, ttd); |
add_dhcp_cname(crec, ttd); |
Line 1154 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1290 void cache_add_dhcp_entry(char *host_name, int prot,
|
} |
} |
#endif |
#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 = bufflen - (p - buff ); |
|
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 = bufflen - (p - buff ); |
|
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; |
|
} |
|
|
|
/* There can be names in the cache containing control chars, don't |
|
mess up logging or open security holes. */ |
|
static char *sanitise(char *name) |
|
{ |
|
unsigned char *r; |
|
if (name) |
|
for (r = (unsigned char *)name; *r; r++) |
|
if (!isprint((int)*r)) |
|
return "<name unprintable>"; |
|
|
|
return name; |
|
} |
|
|
|
|
void dump_cache(time_t now) |
void dump_cache(time_t now) |
{ |
{ |
struct server *serv, *serv1; |
struct server *serv, *serv1; |
|
char *t = ""; |
|
|
my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now); |
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."), |
my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."), |
daemon->cachesize, cache_live_freed, cache_inserted); |
daemon->cachesize, cache_live_freed, cache_inserted); |
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), |
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), |
daemon->queries_forwarded, daemon->local_answer); |
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 */ |
/* sum counts from different records for same server */ |
for (serv = daemon->servers; serv; serv = serv->next) |
for (serv = daemon->servers; serv; serv = serv->next) |
Line 1192 void dump_cache(time_t now)
|
Line 1444 void dump_cache(time_t now)
|
{ |
{ |
struct crec *cache ; |
struct crec *cache ; |
int i; |
int i; |
my_syslog(LOG_INFO, "Host Address Flags Expires"); | my_syslog(LOG_INFO, "Host Address Flags Expires"); |
|
|
for (i=0; i<hash_size; i++) |
for (i=0; i<hash_size; i++) |
for (cache = hash_table[i]; cache; cache = cache->hash_next) |
for (cache = hash_table[i]; cache; cache = cache->hash_next) |
{ |
{ |
char *a, *p = daemon->namebuff; | char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); |
p += sprintf(p, "%-40.40s ", cache_get_name(cache)); | *a = 0; |
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD)) | if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) |
a = ""; | n = "<Root>"; |
else if (cache->flags & F_CNAME) | p += sprintf(p, "%-30.30s ", sanitise(n)); |
{ | if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) |
a = ""; | a = sanitise(cache_get_cname_target(cache)); |
if (!is_outdated_cname_pointer(cache)) | |
a = cache_get_name(cache->addr.cname.cache); | |
} | |
#ifdef HAVE_DNSSEC |
#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) |
else if (cache->flags & F_DS) |
{ |
{ |
a = daemon->addrbuff; | if (!(cache->flags & F_NEG)) |
sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid, | sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, |
cache->addr.key.algo, cache->addr.key.digest, cache->uid); | 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 |
#endif |
else | else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) |
{ |
{ |
a = daemon->addrbuff; |
a = daemon->addrbuff; |
if (cache->flags & F_IPV4) |
if (cache->flags & F_IPV4) |
Line 1231 void dump_cache(time_t now)
|
Line 1478 void dump_cache(time_t now)
|
#endif |
#endif |
} |
} |
|
|
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a, | if (cache->flags & F_IPV4) |
cache->flags & F_IPV4 ? "4" : "", | t = "4"; |
cache->flags & F_IPV6 ? "6" : "", | else if (cache->flags & F_IPV6) |
cache->flags & F_DNSKEY ? "K" : "", | t = "6"; |
cache->flags & F_DS ? "S" : "", | else if (cache->flags & F_CNAME) |
cache->flags & F_CNAME ? "C" : "", | t = "C"; |
| #ifdef HAVE_DNSSEC |
| else if (cache->flags & F_DS) |
| t = "S"; |
| else if (cache->flags & F_DNSKEY) |
| t = "K"; |
| #endif |
| p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t, |
cache->flags & F_FORWARD ? "F" : " ", |
cache->flags & F_FORWARD ? "F" : " ", |
cache->flags & F_REVERSE ? "R" : " ", |
cache->flags & F_REVERSE ? "R" : " ", |
cache->flags & F_IMMORTAL ? "I" : " ", |
cache->flags & F_IMMORTAL ? "I" : " ", |
Line 1257 void dump_cache(time_t now)
|
Line 1511 void dump_cache(time_t now)
|
} |
} |
} |
} |
|
|
char *record_source(int index) | char *record_source(unsigned int index) |
{ |
{ |
struct hostsfile *ah; |
struct hostsfile *ah; |
|
|
if (index == 0) | if (index == SRC_CONFIG) |
| return "config"; |
| else if (index == SRC_HOSTS) |
return HOSTSFILE; |
return HOSTSFILE; |
|
|
for (ah = daemon->addn_hosts; ah; ah = ah->next) |
for (ah = daemon->addn_hosts; ah; ah = ah->next) |
if (ah->index == index) |
if (ah->index == index) |
return ah->fname; |
return ah->fname; |
| |
| #ifdef HAVE_INOTIFY |
| for (ah = daemon->dynamic_dirs; ah; ah = ah->next) |
| if (ah->index == index) |
| return ah->fname; |
| #endif |
| |
return "<unknown>"; |
return "<unknown>"; |
} |
} |
|
|
void querystr(char *desc, char *str, unsigned short type) | char *querystr(char *desc, unsigned short type) |
{ |
{ |
unsigned int i; |
unsigned int i; |
| int len = 10; /* strlen("type=xxxxx") */ |
sprintf(str, "%s[type=%d]", desc, type); | const char *types = NULL; |
| static char *buff = NULL; |
| static int bufflen = 0; |
| |
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) |
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) |
if (typestr[i].type == type) |
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) |
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) |
Line 1289 void log_query(unsigned int flags, char *name, struct
|
Line 1582 void log_query(unsigned int flags, char *name, struct
|
if (!option_bool(OPT_LOG)) |
if (!option_bool(OPT_LOG)) |
return; |
return; |
|
|
|
name = sanitise(name); |
|
|
if (addr) |
if (addr) |
{ |
{ |
|
if (flags & F_KEYTAG) |
|
sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest); |
|
else |
|
{ |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, | inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, |
addr, daemon->addrbuff, ADDRSTRLEN); | addr, daemon->addrbuff, ADDRSTRLEN); |
#else |
#else |
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN); | strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN); |
#endif |
#endif |
|
} |
} |
} |
|
else |
|
dest = arg; |
|
|
if (flags & F_REVERSE) |
if (flags & F_REVERSE) |
{ |
{ |
Line 1308 void log_query(unsigned int flags, char *name, struct
|
Line 1610 void log_query(unsigned int flags, char *name, struct
|
if (flags & F_NEG) |
if (flags & F_NEG) |
{ |
{ |
if (flags & F_NXDOMAIN) |
if (flags & F_NXDOMAIN) |
{ | dest = "NXDOMAIN"; |
if (flags & F_IPV4) | |
dest = "NXDOMAIN-IPv4"; | |
else if (flags & F_IPV6) | |
dest = "NXDOMAIN-IPv6"; | |
else | |
dest = "NXDOMAIN"; | |
} | |
else |
else |
{ |
{ |
if (flags & F_IPV4) |
if (flags & F_IPV4) |
Line 1339 void log_query(unsigned int flags, char *name, struct
|
Line 1634 void log_query(unsigned int flags, char *name, struct
|
source = arg; |
source = arg; |
else if (flags & F_UPSTREAM) |
else if (flags & F_UPSTREAM) |
source = "reply"; |
source = "reply"; |
|
else if (flags & F_SECSTAT) |
|
source = "validation"; |
else if (flags & F_AUTH) |
else if (flags & F_AUTH) |
source = "auth"; |
source = "auth"; |
else if (flags & F_SERVER) |
else if (flags & F_SERVER) |
Line 1351 void log_query(unsigned int flags, char *name, struct
|
Line 1648 void log_query(unsigned int flags, char *name, struct
|
source = arg; |
source = arg; |
verb = "from"; |
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 |
else |
source = "cached"; |
source = "cached"; |
|
|
if (strlen(name) == 0) |
if (strlen(name) == 0) |
name = "."; |
name = "."; |
|
|
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); | if (option_bool(OPT_EXTRALOG)) |
} | |
| |
#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) | int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2); |
{ | if (flags & F_NOEXTRA) |
block = keyblock_free; | my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest); |
keyblock_free = block->next; | |
} | |
else |
else |
block = whine_malloc(sizeof(struct keydata)); | my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest); |
| |
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; | |
} |
} |
| else |
return ret; | my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); |
} |
} |
|
|
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 | |
| |
| |