|
version 1.1.1.3, 2016/11/02 09:57:01
|
version 1.1.1.4, 2021/03/17 00:56:46
|
|
Line 1
|
Line 1
|
| /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2021 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 21 static struct crec *cache_head = NULL, *cache_tail = N
|
Line 21 static struct crec *cache_head = NULL, *cache_tail = N
|
| static struct crec *dhcp_spare = NULL; |
static struct crec *dhcp_spare = NULL; |
| #endif |
#endif |
| static struct crec *new_chain = NULL; |
static struct crec *new_chain = NULL; |
| static int cache_inserted = 0, cache_live_freed = 0, insert_error; | static int 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 void make_non_terminals(struct crec *source); |
| |
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class, |
| |
time_t now, unsigned long ttl, unsigned int flags); |
| |
|
| /* 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 { |
| unsigned int type; |
unsigned int type; |
|
Line 45 static const struct {
|
Line 49 static const struct {
|
| { 24, "SIG" }, |
{ 24, "SIG" }, |
| { 25, "KEY" }, |
{ 25, "KEY" }, |
| { 28, "AAAA" }, |
{ 28, "AAAA" }, |
| |
{ 29, "LOC" }, |
| { 33, "SRV" }, |
{ 33, "SRV" }, |
| { 35, "NAPTR" }, |
{ 35, "NAPTR" }, |
| { 36, "KX" }, |
{ 36, "KX" }, |
|
Line 57 static const struct {
|
Line 62 static const struct {
|
| { 47, "NSEC" }, |
{ 47, "NSEC" }, |
| { 48, "DNSKEY" }, |
{ 48, "DNSKEY" }, |
| { 50, "NSEC3" }, |
{ 50, "NSEC3" }, |
| |
{ 51, "NSEC3PARAM" }, |
| |
{ 52, "TLSA" }, |
| |
{ 53, "SMIMEA" }, |
| |
{ 55, "HIP" }, |
| { 249, "TKEY" }, |
{ 249, "TKEY" }, |
| { 250, "TSIG" }, |
{ 250, "TSIG" }, |
| { 251, "IXFR" }, |
{ 251, "IXFR" }, |
| { 252, "AXFR" }, |
{ 252, "AXFR" }, |
| { 253, "MAILB" }, |
{ 253, "MAILB" }, |
| { 254, "MAILA" }, |
{ 254, "MAILA" }, |
| { 255, "ANY" } | { 255, "ANY" }, |
| | { 257, "CAA" } |
| }; |
}; |
| |
|
| static void cache_free(struct crec *crecp); |
static void cache_free(struct crec *crecp); |
|
Line 72 static void cache_link(struct crec *crecp);
|
Line 82 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) | void next_uid(struct crec *crecp) |
| { |
{ |
| static unsigned int uid = 0; |
static unsigned int uid = 0; |
| |
|
| uid++; | if (crecp->uid == UID_NONE) |
| | { |
| | uid++; |
| |
|
| /* uid == 0 used to indicate CNAME to interface name. */ | /* uid == 0 used to indicate CNAME to interface name. */ |
| if (uid == SRC_INTERFACE) | if (uid == UID_NONE) |
| uid++; | uid++; |
| | |
| return uid; | crecp->uid = uid; |
| | } |
| } |
} |
| |
|
| void cache_init(void) |
void cache_init(void) |
|
Line 100 void cache_init(void)
|
Line 113 void cache_init(void)
|
| { |
{ |
| cache_link(crecp); |
cache_link(crecp); |
| crecp->flags = 0; |
crecp->flags = 0; |
| crecp->uid = next_uid(); | crecp->uid = UID_NONE; |
| } |
} |
| } |
} |
| |
|
|
Line 185 static void cache_hash(struct crec *crecp)
|
Line 198 static void cache_hash(struct crec *crecp)
|
| *up = crecp; |
*up = crecp; |
| } |
} |
| |
|
| #ifdef HAVE_DNSSEC |
|
| static void cache_blockdata_free(struct crec *crecp) |
static void cache_blockdata_free(struct crec *crecp) |
| { |
{ |
| if (crecp->flags & F_DNSKEY) | if (!(crecp->flags & F_NEG)) |
| blockdata_free(crecp->addr.key.keydata); | { |
| else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG)) | if (crecp->flags & F_SRV) |
| blockdata_free(crecp->addr.ds.keydata); | blockdata_free(crecp->addr.srv.target); |
| } | #ifdef HAVE_DNSSEC |
| | else if (crecp->flags & F_DNSKEY) |
| | blockdata_free(crecp->addr.key.keydata); |
| | else if (crecp->flags & F_DS) |
| | blockdata_free(crecp->addr.ds.keydata); |
| #endif |
#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 = next_uid(); /* invalidate CNAMES pointing to this. */ | crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */ |
| |
|
| if (cache_tail) |
if (cache_tail) |
| cache_tail->next = crecp; |
cache_tail->next = crecp; |
|
Line 217 static void cache_free(struct crec *crecp)
|
Line 235 static void cache_free(struct crec *crecp)
|
| crecp->flags &= ~F_BIGNAME; |
crecp->flags &= ~F_BIGNAME; |
| } |
} |
| |
|
| #ifdef HAVE_DNSSEC |
|
| cache_blockdata_free(crecp); |
cache_blockdata_free(crecp); |
| #endif |
|
| } |
} |
| |
|
| /* insert a new cache entry at the head of the list (youngest entry) */ |
/* insert a new cache entry at the head of the list (youngest entry) */ |
|
Line 260 char *cache_get_name(struct crec *crecp)
|
Line 276 char *cache_get_name(struct crec *crecp)
|
| |
|
| char *cache_get_cname_target(struct crec *crecp) |
char *cache_get_cname_target(struct crec *crecp) |
| { |
{ |
| if (crecp->addr.cname.uid != SRC_INTERFACE) | if (crecp->addr.cname.is_name_ptr) |
| | return crecp->addr.cname.target.name; |
| | else |
| return cache_get_name(crecp->addr.cname.target.cache); |
return cache_get_name(crecp->addr.cname.target.cache); |
| |
|
| return crecp->addr.cname.target.int_name->name; |
|
| } |
} |
| |
|
| |
|
|
Line 293 struct crec *cache_enumerate(int init)
|
Line 309 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) || crecp->addr.cname.uid == SRC_INTERFACE) | if (!(crecp->flags & F_CNAME) || crecp->addr.cname.is_name_ptr) |
| 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.target.cache && |
if (crecp->addr.cname.target.cache && |
| (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && | !(crecp->addr.cname.target.cache->flags & (F_DNSKEY | F_DS)) && |
| crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid) |
crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid) |
| return 0; |
return 0; |
| |
|
|
Line 317 static int is_expired(time_t now, struct crec *crecp)
|
Line 333 static int is_expired(time_t now, struct crec *crecp)
|
| return 1; |
return 1; |
| } |
} |
| |
|
| static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) | static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now, |
| | unsigned int flags, struct crec **target_crec, unsigned int *target_uid) |
| { |
{ |
| /* 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 330 static struct crec *cache_scan_free(char *name, struct
|
Line 347 static struct crec *cache_scan_free(char *name, struct
|
| to a cache entry if the 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. |
| | |
| | If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid. |
| | This entry will get re-used with the same name, to preserve CNAMEs. */ |
| |
|
| struct crec *crecp, **up; |
struct crec *crecp, **up; |
| |
|
| |
(void)class; |
| |
|
| 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)) |
|
| { |
|
| *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)) |
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 */ |
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ |
| if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || | if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) || |
| (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) |
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS)))) |
| { |
{ |
| if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
| return crecp; |
return crecp; |
| *up = crecp->hash_next; |
*up = crecp->hash_next; |
| |
/* If this record is for the name we're inserting and is the target |
| |
of a CNAME record. Make the new record for the same name, in the same |
| |
crec, with the same uid to avoid breaking the existing CNAME. */ |
| |
if (crecp->uid != UID_NONE) |
| |
{ |
| |
if (target_crec) |
| |
*target_crec = crecp; |
| |
if (target_uid) |
| |
*target_uid = crecp->uid; |
| |
} |
| cache_unlink(crecp); |
cache_unlink(crecp); |
| cache_free(crecp); |
cache_free(crecp); |
| continue; |
continue; |
|
Line 365 static struct crec *cache_scan_free(char *name, struct
|
Line 386 static struct crec *cache_scan_free(char *name, struct
|
| |
|
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| /* Deletion has to be class-sensitive for DS and DNSKEY */ |
/* 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 ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == class) |
| { |
{ |
| if (crecp->flags & F_CONFIG) |
if (crecp->flags & F_CONFIG) |
| return crecp; |
return crecp; |
|
Line 376 static struct crec *cache_scan_free(char *name, struct
|
Line 397 static struct crec *cache_scan_free(char *name, struct
|
| } |
} |
| #endif |
#endif |
| } |
} |
| |
|
| |
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; |
| |
} |
| |
|
| up = &crecp->hash_next; |
up = &crecp->hash_next; |
| } |
} |
| } |
} |
| else |
else |
| { |
{ |
| int i; |
int i; |
| #ifdef HAVE_IPV6 |
|
| int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ; |
int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ; |
| #else | |
| int addrlen = INADDRSZ; | |
| #endif | |
| for (i = 0; i < hash_size; i++) |
for (i = 0; i < hash_size; i++) |
| for (crecp = hash_table[i], up = &hash_table[i]; |
for (crecp = hash_table[i], up = &hash_table[i]; |
| crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL)); |
crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL)); |
|
Line 403 static struct crec *cache_scan_free(char *name, struct
|
Line 433 static struct crec *cache_scan_free(char *name, struct
|
| else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && |
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, addrlen) == 0) |
| { |
{ |
| *up = crecp->hash_next; |
*up = crecp->hash_next; |
| cache_unlink(crecp); |
cache_unlink(crecp); |
|
Line 438 void cache_start_insert(void)
|
Line 468 void cache_start_insert(void)
|
| new_chain = NULL; |
new_chain = NULL; |
| insert_error = 0; |
insert_error = 0; |
| } |
} |
| |
|
| struct crec *cache_insert(char *name, struct all_addr *addr, |
|
| time_t now, unsigned long ttl, unsigned short flags) |
|
| { |
|
| struct crec *new; |
|
| union bigname *big_name = NULL; |
|
| int freed_all = flags & F_REVERSE; |
|
| int free_avail = 0; |
|
| |
|
| /* Don't log DNSSEC records here, done elsewhere */ | struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class, |
| if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) | time_t now, unsigned long ttl, unsigned int flags) |
| | { |
| | #ifdef HAVE_DNSSEC |
| | if (flags & (F_DNSKEY | F_DS)) |
| { |
{ |
| |
/* The DNSSEC validation process works by getting needed records into the |
| |
cache, then retrying the validation until they are all in place. |
| |
This can be messed up by very short TTLs, and _really_ messed up by |
| |
zero TTLs, so we force the TTL to be at least long enough to do a validation. |
| |
Ideally, we should use some kind of reference counting so that records are |
| |
locked until the validation that asked for them is complete, but this |
| |
is much easier, and just as effective. */ |
| |
if (ttl < DNSSEC_MIN_TTL) |
| |
ttl = DNSSEC_MIN_TTL; |
| |
} |
| |
else |
| |
#endif |
| |
{ |
| |
/* Don't log DNSSEC records here, done elsewhere */ |
| log_query(flags | F_UPSTREAM, name, addr, NULL); |
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) |
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) |
| ttl = daemon->max_cache_ttl; |
ttl = daemon->max_cache_ttl; |
| if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |
| ttl = daemon->min_cache_ttl; |
ttl = daemon->min_cache_ttl; |
| } | } |
| | |
| | return really_insert(name, addr, class, now, ttl, flags); |
| | } |
| |
|
| |
|
| |
static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class, |
| |
time_t now, unsigned long ttl, unsigned int flags) |
| |
{ |
| |
struct crec *new, *target_crec = NULL; |
| |
union bigname *big_name = NULL; |
| |
int freed_all = flags & F_REVERSE; |
| |
int free_avail = 0; |
| |
unsigned int target_uid; |
| |
|
| /* if previous insertion failed give up now. */ |
/* if previous insertion failed give up now. */ |
| if (insert_error) |
if (insert_error) |
| return NULL; |
return NULL; |
| |
|
| |
/* we don't cache zero-TTL records. */ |
| |
if (ttl == 0) |
| |
{ |
| |
insert_error = 1; |
| |
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. */ |
are currently inserting. */ |
| if ((new = cache_scan_free(name, addr, now, flags))) | if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid))) |
| { |
{ |
| /* We're trying to insert a record over one from |
/* We're trying to insert a record over one from |
| /etc/hosts or DHCP, or other config. If the |
/etc/hosts or DHCP, or other config. If the |
| existing record is for an A or AAAA and | existing record is for an A or AAAA or CNAME and |
| the record we're trying to insert is the same, |
the record we're trying to insert is the same, |
| just drop the insert, but don't error the whole process. */ |
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 | F_IPV6)) && (flags & F_FORWARD) && addr) |
| { |
{ |
| if ((flags & F_IPV4) && (new->flags & F_IPV4) && |
if ((flags & F_IPV4) && (new->flags & F_IPV4) && |
| new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr) | new->addr.addr4.s_addr == addr->addr4.s_addr) |
| return new; |
return new; |
| #ifdef HAVE_IPV6 |
|
| else if ((flags & F_IPV6) && (new->flags & F_IPV6) && |
else if ((flags & F_IPV6) && (new->flags & F_IPV6) && |
| IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6)) | IN6_ARE_ADDR_EQUAL(&new->addr.addr6, &addr->addr6)) |
| return new; |
return new; |
| #endif |
|
| } |
} |
| | |
| insert_error = 1; |
insert_error = 1; |
| return NULL; |
return NULL; |
| } |
} |
| |
|
| /* Now get a cache entry from the end of the LRU list */ |
/* Now get a cache entry from the end of the LRU list */ |
| while (1) { | if (!target_crec) |
| if (!(new = cache_tail)) /* no entries left - cache is too small, bail */ | while (1) { |
| { | if (!(new = cache_tail)) /* no entries left - cache is too small, bail */ |
| insert_error = 1; | { |
| return NULL; | insert_error = 1; |
| } | return NULL; |
| | } |
| /* End of LRU list is still in use: if we didn't scan all the hash | |
| chains for expired entries do that now. If we already tried that | /* Free entry at end of LRU list, use it. */ |
| then it's time to start spilling things. */ | if (!(new->flags & (F_FORWARD | F_REVERSE))) |
| | break; |
| if (new->flags & (F_FORWARD | F_REVERSE)) | |
| { | |
| /* If free_avail set, we believe that an entry has been freed. | |
| Bugs have been known to make this not true, resulting in | |
| a tight loop here. If that happens, abandon the | |
| 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 | /* End of LRU list is still in use: if we didn't scan all the hash |
| /* For DNSSEC records, addr holds class. */ | chains for expired entries do that now. If we already tried that |
| if (new->flags & (F_DS | F_DNSKEY)) | then it's time to start spilling things. */ |
| free_addr.addr.dnssec.class = new->uid; | |
| #endif | /* If free_avail set, we believe that an entry has been freed. |
| | Bugs have been known to make this not true, resulting in |
| free_avail = 1; /* Must be free space now. */ | a tight loop here. If that happens, abandon the |
| cache_scan_free(cache_get_name(new), &free_addr, now, new->flags); | insert. Once in this state, all inserts will probably fail. */ |
| cache_live_freed++; | if (free_avail) |
| } | { |
| else | static int warned = 0; |
| { | if (!warned) |
| cache_scan_free(NULL, NULL, now, 0); | { |
| freed_all = 1; | my_syslog(LOG_ERR, _("Internal error in cache.")); |
| } | warned = 1; |
| continue; | } |
| } | insert_error = 1; |
| | return NULL; |
| /* Check if we need to and can allocate extra memory for a long name. | } |
| If that fails, give up now, always succeed for DNSSEC records. */ | |
| if (name && (strlen(name) > SMALLDNAME-1)) | if (freed_all) |
| { | { |
| if (big_free) | /* For DNSSEC records, uid holds class. */ |
| { | free_avail = 1; /* Must be free space now. */ |
| big_name = big_free; | cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL); |
| big_free = big_free->next; | daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++; |
| } | } |
| else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) || | else |
| !(big_name = (union bigname *)whine_malloc(sizeof(union bigname)))) | { |
| { | cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL); |
| insert_error = 1; | freed_all = 1; |
| return NULL; | } |
| } | } |
| else if (bignames_left != 0) | |
| bignames_left--; | /* Check if we need to and can allocate extra memory for a long name. |
| | If that fails, give up now, always succeed for DNSSEC records. */ |
| } | if (name && (strlen(name) > SMALLDNAME-1)) |
| | { |
| | if (big_free) |
| | { |
| | big_name = big_free; |
| | big_free = big_free->next; |
| | } |
| | 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 if (bignames_left != 0) |
| | bignames_left--; |
| | |
| | } |
| |
|
| /* Got the rest: finally grab entry. */ | /* If we freed a cache entry for our name which was a CNAME target, use that. |
| cache_unlink(new); | and preserve the uid, so that existing CNAMES are not broken. */ |
| break; | if (target_crec) |
| } | { |
| | new = target_crec; |
| | new->uid = target_uid; |
| | } |
| |
|
| |
/* Got the rest: finally grab entry. */ |
| |
cache_unlink(new); |
| |
|
| new->flags = flags; |
new->flags = flags; |
| if (big_name) |
if (big_name) |
| { |
{ |
|
Line 576 struct crec *cache_insert(char *name, struct all_addr
|
Line 633 struct crec *cache_insert(char *name, struct all_addr
|
| else |
else |
| *cache_get_name(new) = 0; |
*cache_get_name(new) = 0; |
| |
|
| if (addr) |
|
| { |
|
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| if (flags & (F_DS | F_DNSKEY)) | if (flags & (F_DS | F_DNSKEY)) |
| new->uid = addr->addr.dnssec.class; | new->uid = class; |
| else | |
| #endif |
#endif |
| new->addr.addr = *addr; |
|
| } |
|
| |
|
| |
if (addr) |
| |
new->addr = *addr; |
| |
|
| new->ttd = now + (time_t)ttl; |
new->ttd = now + (time_t)ttl; |
| new->next = new_chain; |
new->next = new_chain; |
| new_chain = new; |
new_chain = new; |
|
Line 609 void cache_end_insert(void)
|
Line 664 void cache_end_insert(void)
|
| { |
{ |
| cache_hash(new_chain); |
cache_hash(new_chain); |
| cache_link(new_chain); |
cache_link(new_chain); |
| cache_inserted++; | daemon->metrics[METRIC_DNS_CACHE_INSERTED]++; |
| | |
| | /* If we're a child process, send this cache entry up the pipe to the master. |
| | The marshalling process is rather nasty. */ |
| | if (daemon->pipe_to_parent != -1) |
| | { |
| | char *name = cache_get_name(new_chain); |
| | ssize_t m = strlen(name); |
| | unsigned int flags = new_chain->flags; |
| | #ifdef HAVE_DNSSEC |
| | u16 class = new_chain->uid; |
| | #endif |
| | |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0); |
| | read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0); |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0); |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0); |
| | |
| | if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV)) |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0); |
| | if (flags & F_SRV) |
| | { |
| | /* A negative SRV entry is possible and has no data, obviously. */ |
| | if (!(flags & F_NEG)) |
| | blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent); |
| | } |
| | #ifdef HAVE_DNSSEC |
| | if (flags & F_DNSKEY) |
| | { |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0); |
| | blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent); |
| | } |
| | else if (flags & F_DS) |
| | { |
| | read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0); |
| | /* A negative DS entry is possible and has no data, obviously. */ |
| | if (!(flags & F_NEG)) |
| | blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent); |
| | } |
| | #endif |
| | } |
| } |
} |
| |
|
| new_chain = tmp; |
new_chain = tmp; |
| } |
} |
| |
|
| |
/* signal end of cache insert in master process */ |
| |
if (daemon->pipe_to_parent != -1) |
| |
{ |
| |
ssize_t m = -1; |
| |
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0); |
| |
} |
| |
|
| new_chain = NULL; |
new_chain = NULL; |
| } |
} |
| |
|
| |
|
| |
/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */ |
| |
int cache_recv_insert(time_t now, int fd) |
| |
{ |
| |
ssize_t m; |
| |
union all_addr addr; |
| |
unsigned long ttl; |
| |
time_t ttd; |
| |
unsigned int flags; |
| |
struct crec *crecp = NULL; |
| |
|
| |
cache_start_insert(); |
| |
|
| |
while(1) |
| |
{ |
| |
|
| |
if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1)) |
| |
return 0; |
| |
|
| |
if (m == -1) |
| |
{ |
| |
cache_end_insert(); |
| |
return 1; |
| |
} |
| |
|
| |
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) || |
| |
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) || |
| |
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1)) |
| |
return 0; |
| |
|
| |
daemon->namebuff[m] = 0; |
| |
|
| |
ttl = difftime(ttd, now); |
| |
|
| |
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV)) |
| |
{ |
| |
unsigned short class = C_IN; |
| |
|
| |
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1)) |
| |
return 0; |
| |
|
| |
if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen))) |
| |
return 0; |
| |
|
| |
#ifdef HAVE_DNSSEC |
| |
if (flags & F_DNSKEY) |
| |
{ |
| |
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) || |
| |
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen))) |
| |
return 0; |
| |
} |
| |
else if (flags & F_DS) |
| |
{ |
| |
if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) || |
| |
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))) |
| |
return 0; |
| |
} |
| |
#endif |
| |
|
| |
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags); |
| |
} |
| |
else if (flags & F_CNAME) |
| |
{ |
| |
struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags); |
| |
/* This relies on the fact that the target of a CNAME immediately precedes |
| |
it because of the order of extraction in extract_addresses, and |
| |
the order reversal on the new_chain. */ |
| |
if (newc) |
| |
{ |
| |
newc->addr.cname.is_name_ptr = 0; |
| |
|
| |
if (!crecp) |
| |
newc->addr.cname.target.cache = NULL; |
| |
else |
| |
{ |
| |
next_uid(crecp); |
| |
newc->addr.cname.target.cache = crecp; |
| |
newc->addr.cname.uid = crecp->uid; |
| |
} |
| |
} |
| |
} |
| |
} |
| |
} |
| |
|
| |
int cache_find_non_terminal(char *name, time_t now) |
| |
{ |
| |
struct crec *crecp; |
| |
|
| |
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next) |
| |
if (!is_outdated_cname_pointer(crecp) && |
| |
!is_expired(now, crecp) && |
| |
(crecp->flags & F_FORWARD) && |
| |
!(crecp->flags & F_NXDOMAIN) && |
| |
hostname_isequal(name, cache_get_name(crecp))) |
| |
return 1; |
| |
|
| |
return 0; |
| |
} |
| |
|
| struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) |
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) |
| { |
{ |
| struct crec *ans; |
struct crec *ans; |
|
Line 630 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 833 struct crec *cache_find_by_name(struct crec *crecp, ch
|
| /* first search, look for relevant entries and push to top of list |
/* first search, look for relevant entries and push to top of list |
| also free anything which has expired */ |
also free anything which has expired */ |
| struct crec *next, **up, **insert = NULL, **chainp = &ans; |
struct crec *next, **up, **insert = NULL, **chainp = &ans; |
| unsigned short ins_flags = 0; | unsigned int ins_flags = 0; |
| |
|
| for (up = hash_bucket(name), crecp = *up; crecp; crecp = next) |
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next) |
| { |
{ |
|
Line 703 struct crec *cache_find_by_name(struct crec *crecp, ch
|
Line 906 struct crec *cache_find_by_name(struct crec *crecp, ch
|
| return NULL; |
return NULL; |
| } |
} |
| |
|
| struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, | struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr, |
| time_t now, unsigned int prot) |
time_t now, unsigned int prot) |
| { |
{ |
| struct crec *ans; |
struct crec *ans; |
| #ifdef HAVE_IPV6 |
|
| int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ; |
int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ; |
| #else |
|
| int addrlen = INADDRSZ; |
|
| #endif |
|
| |
|
| if (crecp) /* iterating */ |
if (crecp) /* iterating */ |
| ans = crecp->next; |
ans = crecp->next; |
|
Line 731 struct crec *cache_find_by_addr(struct crec *crecp, st
|
Line 930 struct crec *cache_find_by_addr(struct crec *crecp, st
|
| if (!is_expired(now, crecp)) |
if (!is_expired(now, crecp)) |
| { |
{ |
| if ((crecp->flags & prot) && |
if ((crecp->flags & prot) && |
| memcmp(&crecp->addr.addr, addr, addrlen) == 0) | memcmp(&crecp->addr, addr, addrlen) == 0) |
| { |
{ |
| if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) |
| { |
{ |
|
Line 762 struct crec *cache_find_by_addr(struct crec *crecp, st
|
Line 961 struct crec *cache_find_by_addr(struct crec *crecp, st
|
| if (ans && |
if (ans && |
| (ans->flags & F_REVERSE) && |
(ans->flags & F_REVERSE) && |
| (ans->flags & prot) && |
(ans->flags & prot) && |
| memcmp(&ans->addr.addr, addr, addrlen) == 0) | memcmp(&ans->addr, addr, addrlen) == 0) |
| return ans; |
return ans; |
| |
|
| return NULL; |
return NULL; |
| } |
} |
| |
|
| static void add_hosts_cname(struct crec *target) | static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen, |
| { | |
| struct crec *crec; | |
| struct cname *a; | |
| | |
| for (a = daemon->cnames; a; a = a->next) | |
| if (hostname_isequal(cache_get_name(target), a->target) && | |
| (crec = whine_malloc(sizeof(struct crec)))) | |
| { | |
| crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME; | |
| crec->ttd = a->ttl; | |
| crec->name.namep = a->alias; | |
| 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, | |
| unsigned 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; |
| unsigned int j; |
unsigned int j; |
| |
|
| /* Remove duplicates in hosts files. */ |
/* Remove duplicates in hosts files. */ |
| if (lookup && (lookup->flags & F_HOSTS)) | if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0) |
| { |
{ |
| nameexists = 1; | free(cache); |
| if (memcmp(&lookup->addr.addr, addr, addrlen) == 0) | return; |
| { | |
| free(cache); | |
| return; | |
| } | |
| } |
} |
| | |
| /* Ensure there is only one address -> name mapping (first one trumps) |
/* Ensure there is only one address -> name mapping (first one trumps) |
| We do this by steam here, The entries are kept in hash chains, linked |
We do this by steam here, The entries are kept in hash chains, linked |
| by ->next (which is unused at this point) held in hash buckets in |
by ->next (which is unused at this point) held in hash buckets in |
|
Line 831 static void add_hosts_entry(struct crec *cache, struct
|
Line 1006 static void add_hosts_entry(struct crec *cache, struct
|
| |
|
| for (lookup = rhash[j]; lookup; lookup = lookup->next) |
for (lookup = rhash[j]; lookup; lookup = lookup->next) |
| if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) && |
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) && |
| memcmp(&lookup->addr.addr, addr, addrlen) == 0) | memcmp(&lookup->addr, addr, addrlen) == 0) |
| { |
{ |
| cache->flags &= ~F_REVERSE; |
cache->flags &= ~F_REVERSE; |
| break; |
break; |
|
Line 853 static void add_hosts_entry(struct crec *cache, struct
|
Line 1028 static void add_hosts_entry(struct crec *cache, struct
|
| } |
} |
| |
|
| cache->uid = index; |
cache->uid = index; |
| memcpy(&cache->addr.addr, addr, addrlen); | memcpy(&cache->addr, addr, addrlen); |
| cache_hash(cache); |
cache_hash(cache); |
| | make_non_terminals(cache); |
| /* don't need to do alias stuff for second and subsequent addresses. */ | |
| if (!nameexists) | |
| add_hosts_cname(cache); | |
| } |
} |
| |
|
| static int eatspace(FILE *f) |
static int eatspace(FILE *f) |
|
Line 881 static int eatspace(FILE *f)
|
Line 1053 static int eatspace(FILE *f)
|
| } |
} |
| |
|
| if (c == '\n') |
if (c == '\n') |
| nl = 1; | nl++; |
| } |
} |
| } |
} |
| |
|
|
Line 892 static int gettok(FILE *f, char *token)
|
Line 1064 static int gettok(FILE *f, char *token)
|
| while (1) |
while (1) |
| { |
{ |
| if ((c = getc(f)) == EOF) |
if ((c = getc(f)) == EOF) |
| return (count == 0) ? EOF : 1; | return (count == 0) ? -1 : 1; |
| |
|
| if (isspace(c) || c == '#') |
if (isspace(c) || c == '#') |
| { |
{ |
|
Line 912 int read_hostsfile(char *filename, unsigned int index,
|
Line 1084 int read_hostsfile(char *filename, unsigned int index,
|
| { |
{ |
| FILE *f = fopen(filename, "r"); |
FILE *f = fopen(filename, "r"); |
| char *token = daemon->namebuff, *domain_suffix = NULL; |
char *token = daemon->namebuff, *domain_suffix = NULL; |
| int addr_count = 0, name_count = cache_size, lineno = 0; | int addr_count = 0, name_count = cache_size, lineno = 1; |
| unsigned short flags = 0; | unsigned int flags = 0; |
| struct all_addr addr; | union all_addr addr; |
| int atnl, addrlen = 0; |
int atnl, addrlen = 0; |
| |
|
| if (!f) |
if (!f) |
|
Line 923 int read_hostsfile(char *filename, unsigned int index,
|
Line 1095 int read_hostsfile(char *filename, unsigned int index,
|
| return cache_size; |
return cache_size; |
| } |
} |
| |
|
| eatspace(f); | lineno += eatspace(f); |
| |
|
| while ((atnl = gettok(f, token)) != EOF) | while ((atnl = gettok(f, token)) != -1) |
| { |
{ |
| lineno++; |
|
| |
|
| if (inet_pton(AF_INET, token, &addr) > 0) |
if (inet_pton(AF_INET, token, &addr) > 0) |
| { |
{ |
| flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; |
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; |
| addrlen = INADDRSZ; |
addrlen = INADDRSZ; |
| domain_suffix = get_domain(addr.addr.addr4); | domain_suffix = get_domain(addr.addr4); |
| } |
} |
| #ifdef HAVE_IPV6 |
|
| else if (inet_pton(AF_INET6, token, &addr) > 0) |
else if (inet_pton(AF_INET6, token, &addr) > 0) |
| { |
{ |
| flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; |
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; |
| addrlen = IN6ADDRSZ; |
addrlen = IN6ADDRSZ; |
| domain_suffix = get_domain6(&addr.addr.addr6); | domain_suffix = get_domain6(&addr.addr6); |
| } |
} |
| #endif |
|
| else |
else |
| { |
{ |
| my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); |
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); |
| while (atnl == 0) |
while (atnl == 0) |
| atnl = gettok(f, token); |
atnl = gettok(f, token); |
| |
lineno += atnl; |
| continue; |
continue; |
| } |
} |
| |
|
|
Line 966 int read_hostsfile(char *filename, unsigned int index,
|
Line 1135 int read_hostsfile(char *filename, unsigned int index,
|
| int fqdn, nomem; |
int fqdn, nomem; |
| char *canon; |
char *canon; |
| |
|
| if ((atnl = gettok(f, token)) == EOF) | if ((atnl = gettok(f, token)) == -1) |
| break; |
break; |
| |
|
| fqdn = !!strchr(token, '.'); |
fqdn = !!strchr(token, '.'); |
|
Line 975 int read_hostsfile(char *filename, unsigned int index,
|
Line 1144 int read_hostsfile(char *filename, unsigned int index,
|
| { |
{ |
| /* If set, add a version of the name with a default domain appended */ |
/* If set, add a version of the name with a default domain appended */ |
| if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && |
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && |
| (cache = whine_malloc(sizeof(struct crec) + | (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix)))) |
| strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME))) | |
| { |
{ |
| strcpy(cache->name.sname, canon); |
strcpy(cache->name.sname, canon); |
| strcat(cache->name.sname, "."); |
strcat(cache->name.sname, "."); |
|
Line 986 int read_hostsfile(char *filename, unsigned int index,
|
Line 1154 int read_hostsfile(char *filename, unsigned int index,
|
| add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); |
| name_count++; |
name_count++; |
| } |
} |
| if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME))) | if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1))) |
| { |
{ |
| strcpy(cache->name.sname, canon); |
strcpy(cache->name.sname, canon); |
| cache->flags = flags; |
cache->flags = flags; |
|
Line 1000 int read_hostsfile(char *filename, unsigned int index,
|
Line 1168 int read_hostsfile(char *filename, unsigned int index,
|
| else if (!nomem) |
else if (!nomem) |
| my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno); |
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno); |
| } |
} |
| |
|
| |
lineno += atnl; |
| } |
} |
| |
|
| fclose(f); |
fclose(f); |
|
Line 1020 void cache_reload(void)
|
Line 1190 void cache_reload(void)
|
| struct host_record *hr; |
struct host_record *hr; |
| struct name_list *nl; |
struct name_list *nl; |
| struct cname *a; |
struct cname *a; |
| |
struct crec lrec; |
| |
struct mx_srv_record *mx; |
| |
struct txt_record *txt; |
| struct interface_name *intr; |
struct interface_name *intr; |
| |
struct ptr_record *ptr; |
| |
struct naptr *naptr; |
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| struct ds_config *ds; |
struct ds_config *ds; |
| #endif |
#endif |
| |
|
| cache_inserted = cache_live_freed = 0; | daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0; |
| | daemon->metrics[METRIC_DNS_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); |
cache_blockdata_free(cache); |
| #endif | |
| tmp = cache->hash_next; |
tmp = cache->hash_next; |
| if (cache->flags & (F_HOSTS | F_CONFIG)) |
if (cache->flags & (F_HOSTS | F_CONFIG)) |
| { |
{ |
|
Line 1053 void cache_reload(void)
|
Line 1228 void cache_reload(void)
|
| up = &cache->hash_next; |
up = &cache->hash_next; |
| } |
} |
| |
|
| /* Add CNAMEs to interface_names to the cache */ | /* Add locally-configured CNAMEs to the cache */ |
| for (a = daemon->cnames; a; a = a->next) |
for (a = daemon->cnames; a; a = a->next) |
| for (intr = daemon->int_names; intr; intr = intr->next) | if (a->alias[1] != '*' && |
| if (hostname_isequal(a->target, intr->name) && | ((cache = whine_malloc(SIZEOF_POINTER_CREC)))) |
| ((cache = whine_malloc(sizeof(struct crec))))) | { |
| { | cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; |
| cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; | cache->ttd = a->ttl; |
| cache->ttd = a->ttl; | cache->name.namep = a->alias; |
| cache->name.namep = a->alias; | cache->addr.cname.target.name = a->target; |
| cache->addr.cname.target.int_name = intr; | cache->addr.cname.is_name_ptr = 1; |
| cache->addr.cname.uid = SRC_INTERFACE; | cache->uid = UID_NONE; |
| cache->uid = next_uid(); | cache_hash(cache); |
| cache_hash(cache); | make_non_terminals(cache); |
| add_hosts_cname(cache); /* handle chains */ | } |
| } | |
| |
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| for (ds = daemon->ds; ds; ds = ds->next) |
for (ds = daemon->ds; ds; ds = ds->next) |
| if ((cache = whine_malloc(sizeof(struct crec))) && | if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) && |
| (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen))) |
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen))) |
| { |
{ |
| cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP; |
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP; |
|
Line 1083 void cache_reload(void)
|
Line 1257 void cache_reload(void)
|
| cache->addr.ds.digest = ds->digest_type; |
cache->addr.ds.digest = ds->digest_type; |
| cache->uid = ds->class; |
cache->uid = ds->class; |
| cache_hash(cache); |
cache_hash(cache); |
| |
make_non_terminals(cache); |
| } |
} |
| #endif |
#endif |
| |
|
|
Line 1096 void cache_reload(void)
|
Line 1271 void cache_reload(void)
|
| for (hr = daemon->host_records; hr; hr = hr->next) |
for (hr = daemon->host_records; hr; hr = hr->next) |
| for (nl = hr->names; nl; nl = nl->next) |
for (nl = hr->names; nl; nl = nl->next) |
| { |
{ |
| if (hr->addr.s_addr != 0 && | if ((hr->flags & HR_4) && |
| (cache = whine_malloc(sizeof(struct crec)))) | (cache = whine_malloc(SIZEOF_POINTER_CREC))) |
| { |
{ |
| cache->name.namep = nl->name; |
cache->name.namep = nl->name; |
| cache->ttd = hr->ttl; |
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, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); | add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); |
| } |
} |
| #ifdef HAVE_IPV6 | |
| if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && | if ((hr->flags & HR_6) && |
| (cache = whine_malloc(sizeof(struct crec)))) | (cache = whine_malloc(SIZEOF_POINTER_CREC))) |
| { |
{ |
| cache->name.namep = nl->name; |
cache->name.namep = nl->name; |
| cache->ttd = hr->ttl; |
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, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); | add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz); |
| } |
} |
| #endif |
|
| } |
} |
| |
|
| if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts) |
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts) |
|
Line 1131 void cache_reload(void)
|
Line 1305 void cache_reload(void)
|
| if (!(ah->flags & AH_INACTIVE)) |
if (!(ah->flags & AH_INACTIVE)) |
| total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); |
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); |
| } |
} |
| |
|
| |
/* Make non-terminal records for all locally-define RRs */ |
| |
lrec.flags = F_FORWARD | F_CONFIG | F_NAMEP | F_IMMORTAL; |
| |
|
| |
for (txt = daemon->txt; txt; txt = txt->next) |
| |
{ |
| |
lrec.name.namep = txt->name; |
| |
make_non_terminals(&lrec); |
| |
} |
| |
|
| |
for (naptr = daemon->naptr; naptr; naptr = naptr->next) |
| |
{ |
| |
lrec.name.namep = naptr->name; |
| |
make_non_terminals(&lrec); |
| |
} |
| |
|
| |
for (mx = daemon->mxnames; mx; mx = mx->next) |
| |
{ |
| |
lrec.name.namep = mx->name; |
| |
make_non_terminals(&lrec); |
| |
} |
| |
|
| |
for (intr = daemon->int_names; intr; intr = intr->next) |
| |
{ |
| |
lrec.name.namep = intr->name; |
| |
make_non_terminals(&lrec); |
| |
} |
| |
|
| |
for (ptr = daemon->ptr; ptr; ptr = ptr->next) |
| |
{ |
| |
lrec.name.namep = ptr->name; |
| |
make_non_terminals(&lrec); |
| |
} |
| |
|
| #ifdef HAVE_INOTIFY |
#ifdef HAVE_INOTIFY |
| set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz); |
set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz); |
| #endif |
#endif |
|
Line 1146 struct in_addr a_record_from_hosts(char *name, time_t
|
Line 1353 struct in_addr a_record_from_hosts(char *name, time_t
|
| |
|
| while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4))) |
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4))) |
| if (crecp->flags & F_HOSTS) |
if (crecp->flags & F_HOSTS) |
| return *(struct in_addr *)&crecp->addr; | return crecp->addr.addr4; |
| |
|
| my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name); |
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name); |
| |
|
|
Line 1171 void cache_unhash_dhcp(void)
|
Line 1378 void cache_unhash_dhcp(void)
|
| up = &cache->hash_next; |
up = &cache->hash_next; |
| } |
} |
| |
|
| static void add_dhcp_cname(struct crec *target, time_t ttd) |
|
| { |
|
| struct crec *aliasc; |
|
| struct cname *a; |
|
| |
|
| for (a = daemon->cnames; a; a = a->next) |
|
| if (hostname_isequal(cache_get_name(target), a->target)) |
|
| { |
|
| if ((aliasc = dhcp_spare)) |
|
| dhcp_spare = dhcp_spare->next; |
|
| else /* need new one */ |
|
| aliasc = whine_malloc(sizeof(struct crec)); |
|
| |
|
| if (aliasc) |
|
| { |
|
| 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.target.cache = target; |
|
| aliasc->addr.cname.uid = target->uid; |
|
| aliasc->uid = next_uid(); |
|
| cache_hash(aliasc); |
|
| add_dhcp_cname(aliasc, ttd); |
|
| } |
|
| } |
|
| } |
|
| |
|
| void cache_add_dhcp_entry(char *host_name, int prot, |
void cache_add_dhcp_entry(char *host_name, int prot, |
| struct all_addr *host_address, time_t ttd) | union all_addr *host_address, time_t ttd) |
| { |
{ |
| struct crec *crec = NULL, *fail_crec = NULL; |
struct crec *crec = NULL, *fail_crec = NULL; |
| unsigned short flags = F_IPV4; | unsigned int flags = F_IPV4; |
| int in_hosts = 0; |
int in_hosts = 0; |
| size_t addrlen = sizeof(struct in_addr); |
size_t addrlen = sizeof(struct in_addr); |
| |
|
| #ifdef HAVE_IPV6 |
|
| if (prot == AF_INET6) |
if (prot == AF_INET6) |
| { |
{ |
| flags = F_IPV6; |
flags = F_IPV6; |
| addrlen = sizeof(struct in6_addr); |
addrlen = sizeof(struct in6_addr); |
| } |
} |
| #endif |
|
| |
|
| inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN); |
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN); |
| |
|
|
Line 1228 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1403 void cache_add_dhcp_entry(char *host_name, int prot,
|
| my_syslog(MS_DHCP | LOG_WARNING, |
my_syslog(MS_DHCP | LOG_WARNING, |
| _("%s is a CNAME, not giving it to the DHCP lease of %s"), |
_("%s is a CNAME, not giving it to the DHCP lease of %s"), |
| host_name, daemon->addrbuff); |
host_name, daemon->addrbuff); |
| else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0) | else if (memcmp(&crec->addr, host_address, addrlen) == 0) |
| in_hosts = 1; |
in_hosts = 1; |
| else |
else |
| fail_crec = crec; |
fail_crec = crec; |
| } |
} |
| else if (!(crec->flags & F_DHCP)) |
else if (!(crec->flags & F_DHCP)) |
| { |
{ |
| cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD)); | cache_scan_free(host_name, NULL, C_IN, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL); |
| /* scan_free deletes all addresses associated with name */ |
/* scan_free deletes all addresses associated with name */ |
| break; |
break; |
| } |
} |
|
Line 1248 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1423 void cache_add_dhcp_entry(char *host_name, int prot,
|
| /* Name in hosts, address doesn't match */ |
/* Name in hosts, address doesn't match */ |
| if (fail_crec) |
if (fail_crec) |
| { |
{ |
| inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME); | inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME); |
| my_syslog(MS_DHCP | LOG_WARNING, |
my_syslog(MS_DHCP | LOG_WARNING, |
| _("not giving name %s to the DHCP lease of %s because " |
_("not giving name %s to the DHCP lease of %s because " |
| "the name exists in %s with address %s"), |
"the name exists in %s with address %s"), |
|
Line 1257 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1432 void cache_add_dhcp_entry(char *host_name, int prot,
|
| return; |
return; |
| } |
} |
| |
|
| if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags))) | if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags))) |
| { |
{ |
| if (crec->flags & F_NEG) |
if (crec->flags & F_NEG) |
| { |
{ |
| flags |= F_REVERSE; |
flags |= F_REVERSE; |
| cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags); | cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL); |
| } |
} |
| } |
} |
| else |
else |
|
Line 1271 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1446 void cache_add_dhcp_entry(char *host_name, int prot,
|
| if ((crec = dhcp_spare)) |
if ((crec = dhcp_spare)) |
| dhcp_spare = dhcp_spare->next; |
dhcp_spare = dhcp_spare->next; |
| else /* need new one */ |
else /* need new one */ |
| crec = whine_malloc(sizeof(struct crec)); | crec = whine_malloc(SIZEOF_POINTER_CREC); |
| |
|
| if (crec) /* malloc may fail */ |
if (crec) /* malloc may fail */ |
| { |
{ |
|
Line 1280 void cache_add_dhcp_entry(char *host_name, int prot,
|
Line 1455 void cache_add_dhcp_entry(char *host_name, int prot,
|
| crec->flags |= F_IMMORTAL; |
crec->flags |= F_IMMORTAL; |
| else |
else |
| crec->ttd = ttd; |
crec->ttd = ttd; |
| crec->addr.addr = *host_address; | crec->addr = *host_address; |
| crec->name.namep = host_name; |
crec->name.namep = host_name; |
| crec->uid = next_uid(); | crec->uid = UID_NONE; |
| cache_hash(crec); |
cache_hash(crec); |
| make_non_terminals(crec); |
| add_dhcp_cname(crec, ttd); | |
| } |
} |
| } |
} |
| #endif |
#endif |
| |
|
| |
/* Called when we put a local or DHCP name into the cache. |
| |
Creates empty cache entries for subnames (ie, |
| |
for three.two.one, for two.one and one), without |
| |
F_IPV4 or F_IPV6 or F_CNAME set. These convert |
| |
NXDOMAIN answers to NoData ones. */ |
| |
static void make_non_terminals(struct crec *source) |
| |
{ |
| |
char *name = cache_get_name(source); |
| |
struct crec *crecp, *tmp, **up; |
| |
int type = F_HOSTS | F_CONFIG; |
| |
#ifdef HAVE_DHCP |
| |
if (source->flags & F_DHCP) |
| |
type = F_DHCP; |
| |
#endif |
| |
|
| |
/* First delete any empty entries for our new real name. Note that |
| |
we only delete empty entries deriving from DHCP for a new DHCP-derived |
| |
entry and vice-versa for HOSTS and CONFIG. This ensures that |
| |
non-terminals from DHCP go when we reload DHCP and |
| |
for HOSTS/CONFIG when we re-read. */ |
| |
for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp) |
| |
{ |
| |
tmp = crecp->hash_next; |
| |
|
| |
if (!is_outdated_cname_pointer(crecp) && |
| |
(crecp->flags & F_FORWARD) && |
| |
(crecp->flags & type) && |
| |
!(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS)) && |
| |
hostname_isequal(name, cache_get_name(crecp))) |
| |
{ |
| |
*up = crecp->hash_next; |
| |
#ifdef HAVE_DHCP |
| |
if (type & F_DHCP) |
| |
{ |
| |
crecp->next = dhcp_spare; |
| |
dhcp_spare = crecp; |
| |
} |
| |
else |
| |
#endif |
| |
free(crecp); |
| |
break; |
| |
} |
| |
else |
| |
up = &crecp->hash_next; |
| |
} |
| |
|
| |
while ((name = strchr(name, '.'))) |
| |
{ |
| |
name++; |
| |
|
| |
/* Look for one existing, don't need another */ |
| |
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next) |
| |
if (!is_outdated_cname_pointer(crecp) && |
| |
(crecp->flags & F_FORWARD) && |
| |
(crecp->flags & type) && |
| |
hostname_isequal(name, cache_get_name(crecp))) |
| |
break; |
| |
|
| |
if (crecp) |
| |
{ |
| |
/* If the new name expires later, transfer that time to |
| |
empty non-terminal entry. */ |
| |
if (!(crecp->flags & F_IMMORTAL)) |
| |
{ |
| |
if (source->flags & F_IMMORTAL) |
| |
crecp->flags |= F_IMMORTAL; |
| |
else if (difftime(crecp->ttd, source->ttd) < 0) |
| |
crecp->ttd = source->ttd; |
| |
} |
| |
continue; |
| |
} |
| |
|
| |
#ifdef HAVE_DHCP |
| |
if ((source->flags & F_DHCP) && dhcp_spare) |
| |
{ |
| |
crecp = dhcp_spare; |
| |
dhcp_spare = dhcp_spare->next; |
| |
} |
| |
else |
| |
#endif |
| |
crecp = whine_malloc(SIZEOF_POINTER_CREC); |
| |
|
| |
if (crecp) |
| |
{ |
| |
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE); |
| |
crecp->ttd = source->ttd; |
| |
crecp->name.namep = name; |
| |
|
| |
cache_hash(crecp); |
| |
} |
| |
} |
| |
} |
| |
|
| |
#ifndef NO_ID |
| int cache_make_stat(struct txt_record *t) |
int cache_make_stat(struct txt_record *t) |
| { |
{ |
| static char *buff = NULL; |
static char *buff = NULL; |
|
Line 1310 int cache_make_stat(struct txt_record *t)
|
Line 1578 int cache_make_stat(struct txt_record *t)
|
| break; |
break; |
| |
|
| case TXT_STAT_INSERTS: |
case TXT_STAT_INSERTS: |
| sprintf(buff+1, "%d", cache_inserted); | sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]); |
| break; |
break; |
| |
|
| case TXT_STAT_EVICTIONS: |
case TXT_STAT_EVICTIONS: |
| sprintf(buff+1, "%d", cache_live_freed); | sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]); |
| break; |
break; |
| |
|
| case TXT_STAT_MISSES: |
case TXT_STAT_MISSES: |
| sprintf(buff+1, "%u", daemon->queries_forwarded); | sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]); |
| break; |
break; |
| |
|
| case TXT_STAT_HITS: |
case TXT_STAT_HITS: |
| sprintf(buff+1, "%u", daemon->local_answer); | sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]); |
| break; |
break; |
| |
|
| #ifdef HAVE_AUTH |
#ifdef HAVE_AUTH |
| case TXT_STAT_AUTH: |
case TXT_STAT_AUTH: |
| sprintf(buff+1, "%u", daemon->auth_answer); | sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]); |
| break; |
break; |
| #endif |
#endif |
| |
|
|
Line 1385 int cache_make_stat(struct txt_record *t)
|
Line 1653 int cache_make_stat(struct txt_record *t)
|
| *buff = len; |
*buff = len; |
| return 1; |
return 1; |
| } |
} |
| |
#endif |
| |
|
| /* There can be names in the cache containing control chars, don't |
/* There can be names in the cache containing control chars, don't |
| mess up logging or open security holes. */ |
mess up logging or open security holes. */ |
|
Line 1403 static char *sanitise(char *name)
|
Line 1672 static char *sanitise(char *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, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_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->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]); |
| #ifdef HAVE_AUTH |
#ifdef HAVE_AUTH |
| my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer); | my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]); |
| #endif |
#endif |
| #ifdef HAVE_DNSSEC | |
| blockdata_report(); |
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 1449 void dump_cache(time_t now)
|
Line 1716 void dump_cache(time_t now)
|
| 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 *t = " "; |
| char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); |
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); |
| *a = 0; |
*a = 0; |
| if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) |
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) |
|
Line 1456 void dump_cache(time_t now)
|
Line 1724 void dump_cache(time_t now)
|
| p += sprintf(p, "%-30.30s ", sanitise(n)); |
p += sprintf(p, "%-30.30s ", sanitise(n)); |
| if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) |
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache)) |
| a = sanitise(cache_get_cname_target(cache)); |
a = sanitise(cache_get_cname_target(cache)); |
| |
else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG)) |
| |
{ |
| |
int targetlen = cache->addr.srv.targetlen; |
| |
ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority, |
| |
cache->addr.srv.weight, cache->addr.srv.srvport); |
| |
|
| |
if (targetlen > (40 - len)) |
| |
targetlen = 40 - len; |
| |
blockdata_retrieve(cache->addr.srv.target, targetlen, a + len); |
| |
a[len + targetlen] = 0; |
| |
} |
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| else if (cache->flags & F_DS) |
else if (cache->flags & F_DS) |
| { |
{ |
|
Line 1471 void dump_cache(time_t now)
|
Line 1750 void dump_cache(time_t now)
|
| { |
{ |
| a = daemon->addrbuff; |
a = daemon->addrbuff; |
| if (cache->flags & F_IPV4) |
if (cache->flags & F_IPV4) |
| inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN); | inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN); |
| #ifdef HAVE_IPV6 | |
| else if (cache->flags & F_IPV6) |
else if (cache->flags & F_IPV6) |
| inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN); | inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN); |
| #endif | |
| } |
} |
| |
|
| if (cache->flags & F_IPV4) |
if (cache->flags & F_IPV4) |
|
Line 1484 void dump_cache(time_t now)
|
Line 1761 void dump_cache(time_t now)
|
| t = "6"; |
t = "6"; |
| else if (cache->flags & F_CNAME) |
else if (cache->flags & F_CNAME) |
| t = "C"; |
t = "C"; |
| |
else if (cache->flags & F_SRV) |
| |
t = "V"; |
| #ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
| else if (cache->flags & F_DS) |
else if (cache->flags & F_DS) |
| t = "S"; |
t = "S"; |
|
Line 1506 void dump_cache(time_t now)
|
Line 1785 void dump_cache(time_t now)
|
| /* ctime includes trailing \n - eat it */ |
/* ctime includes trailing \n - eat it */ |
| *(p-1) = 0; |
*(p-1) = 0; |
| #endif |
#endif |
| my_syslog(LOG_INFO, daemon->namebuff); | my_syslog(LOG_INFO, "%s", daemon->namebuff); |
| } |
} |
| } |
} |
| } |
} |
|
Line 1549 char *querystr(char *desc, unsigned short type)
|
Line 1828 char *querystr(char *desc, unsigned short type)
|
| break; |
break; |
| } |
} |
| |
|
| len += 3; /* braces, terminator */ | if (desc) |
| len += strlen(desc); | { |
| len += 2; /* braces */ |
| | len += strlen(desc); |
| | } |
| | len++; /* terminator */ |
| | |
| if (!buff || bufflen < len) |
if (!buff || bufflen < len) |
| { |
{ |
| if (buff) |
if (buff) |
|
Line 1565 char *querystr(char *desc, unsigned short type)
|
Line 1848 char *querystr(char *desc, unsigned short type)
|
| |
|
| if (buff) |
if (buff) |
| { |
{ |
| if (types) | if (desc) |
| sprintf(buff, "%s[%s]", desc, types); | { |
| | if (types) |
| | sprintf(buff, "%s[%s]", desc, types); |
| | else |
| | sprintf(buff, "%s[type=%d]", desc, type); |
| | } |
| else |
else |
| sprintf(buff, "%s[type=%d]", desc, type); | { |
| | if (types) |
| | sprintf(buff, "<%s>", types); |
| | else |
| | sprintf(buff, "type=%d", type); |
| | } |
| } |
} |
| |
| return buff ? buff : ""; |
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, union all_addr *addr, char *arg) |
| { |
{ |
| char *source, *dest = daemon->addrbuff; |
char *source, *dest = daemon->addrbuff; |
| char *verb = "is"; |
char *verb = "is"; |
|
Line 1587 void log_query(unsigned int flags, char *name, struct
|
Line 1880 void log_query(unsigned int flags, char *name, struct
|
| if (addr) |
if (addr) |
| { |
{ |
| if (flags & F_KEYTAG) |
if (flags & F_KEYTAG) |
| sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest); | sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest); |
| else | else if (flags & F_RCODE) |
| { |
{ |
| #ifdef HAVE_IPV6 | unsigned int rcode = addr->log.rcode; |
| inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, | |
| addr, daemon->addrbuff, ADDRSTRLEN); | if (rcode == SERVFAIL) |
| #else | dest = "SERVFAIL"; |
| strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN); | else if (rcode == REFUSED) |
| #endif | dest = "REFUSED"; |
| | else if (rcode == NOTIMP) |
| | dest = "not implemented"; |
| | else |
| | sprintf(daemon->addrbuff, "%u", rcode); |
| } |
} |
| |
else |
| |
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, |
| |
addr, daemon->addrbuff, ADDRSTRLEN); |
| |
|
| } |
} |
| else |
else |
| dest = arg; |
dest = arg; |
|
Line 1623 void log_query(unsigned int flags, char *name, struct
|
Line 1924 void log_query(unsigned int flags, char *name, struct
|
| } |
} |
| else if (flags & F_CNAME) |
else if (flags & F_CNAME) |
| dest = "<CNAME>"; |
dest = "<CNAME>"; |
| |
else if (flags & F_SRV) |
| |
dest = "<SRV>"; |
| else if (flags & F_RRNAME) |
else if (flags & F_RRNAME) |
| dest = arg; |
dest = arg; |
| |
|