"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/cache.c" between
dnsmasq-2.80.tar.gz and dnsmasq-2.81.tar.xz

About: Dnsmasq is a lightweight caching DNS forwarder and DHCP server.

cache.c  (dnsmasq-2.80):cache.c  (dnsmasq-2.81.tar.xz)
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley /* dnsmasq is Copyright (c) 2000-2020 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
the Free Software Foundation; version 2 dated June, 1991, or the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007. (at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 29 skipping to change at line 29
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL; static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
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 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 void make_non_terminals(struct crec *source);
static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
rt class,
time_t now, unsigned long ttl, unsigned int fl
ags);
/* 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;
const char * const name; const char * const name;
} typestr[] = { } typestr[] = {
{ 1, "A" }, { 1, "A" },
{ 2, "NS" }, { 2, "NS" },
{ 5, "CNAME" }, { 5, "CNAME" },
{ 6, "SOA" }, { 6, "SOA" },
skipping to change at line 199 skipping to change at line 201
up = &((*up)->hash_next); up = &((*up)->hash_next);
if (crecp->flags & F_IMMORTAL) if (crecp->flags & F_IMMORTAL)
while (*up && !((*up)->flags & F_IMMORTAL)) while (*up && !((*up)->flags & F_IMMORTAL))
up = &((*up)->hash_next); up = &((*up)->hash_next);
} }
crecp->hash_next = *up; crecp->hash_next = *up;
*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 = UID_NONE; /* 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;
else else
skipping to change at line 231 skipping to change at line 238
cache_tail = crecp; cache_tail = crecp;
/* retrieve big name for further use. */ /* retrieve big name for further use. */
if (crecp->flags & F_BIGNAME) if (crecp->flags & F_BIGNAME)
{ {
crecp->name.bname->next = big_free; crecp->name.bname->next = big_free;
big_free = crecp->name.bname; big_free = crecp->name.bname;
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) */
static void cache_link(struct crec *crecp) static void cache_link(struct crec *crecp)
{ {
if (cache_head) /* check needed for init code */ if (cache_head) /* check needed for init code */
cache_head->prev = crecp; cache_head->prev = crecp;
crecp->next = cache_head; crecp->next = cache_head;
crecp->prev = NULL; crecp->prev = NULL;
cache_head = crecp; cache_head = crecp;
skipping to change at line 274 skipping to change at line 279
if (crecp->flags & F_BIGNAME) if (crecp->flags & F_BIGNAME)
return crecp->name.bname->name; return crecp->name.bname->name;
else if (crecp->flags & F_NAMEP) else if (crecp->flags & F_NAMEP)
return crecp->name.namep; return crecp->name.namep;
return crecp->name.sname; return crecp->name.sname;
} }
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;
} }
struct crec *cache_enumerate(int init) struct crec *cache_enumerate(int init)
{ {
static int bucket; static int bucket;
static struct crec *cache; static struct crec *cache;
if (init) if (init)
{ {
bucket = 0; bucket = 0;
skipping to change at line 305 skipping to change at line 310
while (bucket < hash_size) while (bucket < hash_size)
if ((cache = hash_table[bucket++])) if ((cache = hash_table[bucket++]))
break; break;
} }
return cache; return cache;
} }
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;
return 1; return 1;
} }
static int is_expired(time_t now, struct crec *crecp) static int is_expired(time_t now, struct crec *crecp)
{ {
if (crecp->flags & F_IMMORTAL) if (crecp->flags & F_IMMORTAL)
return 0; return 0;
if (difftime(now, crecp->ttd) < 0) if (difftime(now, crecp->ttd) < 0)
return 0; return 0;
return 1; return 1;
} }
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
w, unsigned short flags, hort class, time_t now,
struct crec **target_crec, unsigned int *targ unsigned int flags, struct crec **target_crec
et_uid) , 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 exp ired If (flags & F_FORWARD) then remove any forward entries for name and any exp ired
entries but only in the same hash bucket as name. entries but only in the same hash bucket as name.
If (flags & F_REVERSE) then remove any reverse entries for addr and any exp ired If (flags & F_REVERSE) then remove any reverse entries for addr and any exp ired
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 a non- NULL pointer In the flags & F_FORWARD case, the return code is valid, and returns a non- NULL pointer
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 <rev erse>,<other>,<immortal> We take advantage of the fact that hash chains have stuff in the order <rev erse>,<other>,<immortal>
so that when we hit an entry which isn't reverse and is immortal, we're don e. so that when we hit an entry which isn't reverse and is immortal, we're don e.
If we free a crec which is a CNAME target, return the entry and uid in targ et_crec and target_uid. If we free a crec which is a CNAME target, return the entry and uid in targ et_crec and target_uid.
This entry will get re-used with the same name, to preserve CNAMEs. */ 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 ((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_DNSK EY | F_DS)))) (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSK EY | 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 ta rget /* If this record is for the name we're inserting and is the ta rget
of a CNAME record. Make the new record for the same name, in the same 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 . */ crec, with the same uid to avoid breaking the existing CNAME . */
if (crecp->uid != UID_NONE) if (crecp->uid != UID_NONE)
{ {
skipping to change at line 380 skipping to change at line 387
if (target_uid) if (target_uid)
*target_uid = crecp->uid; *target_uid = crecp->uid;
} }
cache_unlink(crecp); cache_unlink(crecp);
cache_free(crecp); cache_free(crecp);
continue; continue;
} }
#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 == add r->addr.dnssec.class) if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == cla ss)
{ {
if (crecp->flags & F_CONFIG) if (crecp->flags & F_CONFIG)
return crecp; return crecp;
*up = crecp->hash_next; *up = crecp->hash_next;
cache_unlink(crecp); cache_unlink(crecp);
cache_free(crecp); cache_free(crecp);
continue; continue;
} }
#endif #endif
} }
skipping to change at line 409 skipping to change at line 416
} }
continue; 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) );
crecp = crecp->hash_next) crecp = crecp->hash_next)
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 | F_CONFIG))) 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 | 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);
cache_free(crecp); cache_free(crecp);
} }
else else
up = &crecp->hash_next; up = &crecp->hash_next;
} }
return NULL; return NULL;
skipping to change at line 466 skipping to change at line 470
while (new_chain) while (new_chain)
{ {
struct crec *tmp = new_chain->next; struct crec *tmp = new_chain->next;
cache_free(new_chain); cache_free(new_chain);
new_chain = tmp; new_chain = tmp;
} }
new_chain = NULL; new_chain = NULL;
insert_error = 0; insert_error = 0;
} }
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class
time_t now, unsigned long ttl, unsigned short flags) ,
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;
/* Don't log DNSSEC records here, done elsewhere */ /* Don't log DNSSEC records here, done elsewhere */
if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
{ {
log_query(flags | F_UPSTREAM, name, addr, NULL); log_query(flags | F_UPSTREAM, name, addr, NULL);
/* Don't mess with TTL for DNSSEC records. */ /* 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 sho
rt class,
time_t now, unsigned long ttl, unsigned int fl
ags)
{
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, &target_crec, &target_uid)) ) if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &targe t_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.add r6)) 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 */
if (!target_crec) if (!target_crec)
while (1) { while (1) {
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */ if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
skipping to change at line 550 skipping to change at line 565
{ {
my_syslog(LOG_ERR, _("Internal error in cache.")); my_syslog(LOG_ERR, _("Internal error in cache."));
warned = 1; 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;; /* For DNSSEC records, uid holds class. */
#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), &free_addr, now, new->flags, NULL, NULL); cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->fl ags, NULL, NULL);
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++; daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
} }
else else
{ {
cache_scan_free(NULL, NULL, now, 0, NULL, NULL); cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
freed_all = 1; freed_all = 1;
} }
} }
/* 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, always succeed for DNSSEC records. */ 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)
{ {
skipping to change at line 612 skipping to change at line 620
{ {
new->name.bname = big_name; new->name.bname = big_name;
new->flags |= F_BIGNAME; new->flags |= F_BIGNAME;
} }
if (name) if (name)
strcpy(cache_get_name(new), name); strcpy(cache_get_name(new), name);
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;
return new; return new;
} }
/* after end of insertion, commit the new entries */ /* after end of insertion, commit the new entries */
void cache_end_insert(void) void cache_end_insert(void)
skipping to change at line 646 skipping to change at line 652
{ {
struct crec *tmp = new_chain->next; struct crec *tmp = new_chain->next;
/* drop CNAMEs which didn't find a target. */ /* drop CNAMEs which didn't find a target. */
if (is_outdated_cname_pointer(new_chain)) if (is_outdated_cname_pointer(new_chain))
cache_free(new_chain); cache_free(new_chain);
else else
{ {
cache_hash(new_chain); cache_hash(new_chain);
cache_link(new_chain); cache_link(new_chain);
daemon->metrics[METRIC_DNS_CACHE_INSERTED]++; daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
/* If we're a child process, send this cache entry up the pipe to the m
aster.
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->a
ddr, 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.s
rv.targetlen, daemon->pipe_to_parent);
}
#ifdef HAVE_DNSSEC
if (flags & F_DNSKEY)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, siz
eof(class), 0);
blockdata_write(new_chain->addr.key.keydata, new_chain->addr.ke
y.keylen, daemon->pipe_to_parent);
}
else if (flags & F_DS)
{
read_write(daemon->pipe_to_parent, (unsigned char *)&class, siz
eof(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.d
s.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 cach
e 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 = blockdat
a_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, tt
l, flags);
/* This relies on the fact that the target of a CNAME immediately prece
des
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) int cache_find_non_terminal(char *name, time_t now)
{ {
struct crec *crecp; struct crec *crecp;
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next) for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
if (!is_outdated_cname_pointer(crecp) && if (!is_outdated_cname_pointer(crecp) &&
!is_expired(now, crecp) && !is_expired(now, crecp) &&
(crecp->flags & F_FORWARD) && (crecp->flags & F_FORWARD) &&
!(crecp->flags & F_NXDOMAIN) &&
hostname_isequal(name, cache_get_name(crecp))) hostname_isequal(name, cache_get_name(crecp)))
return 1; return 1;
return 0; return 0;
} }
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi gned int prot) struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi gned int prot)
{ {
struct crec *ans; struct crec *ans;
int no_rr = prot & F_NO_RR; int no_rr = prot & F_NO_RR;
prot &= ~F_NO_RR; prot &= ~F_NO_RR;
if (crecp) /* iterating */ if (crecp) /* iterating */
ans = crecp->next; ans = crecp->next;
else else
{ {
/* 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)
{ {
next = crecp->hash_next; next = crecp->hash_next;
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp)) if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
{ {
if ((crecp->flags & F_FORWARD) && if ((crecp->flags & F_FORWARD) &&
(crecp->flags & prot) && (crecp->flags & prot) &&
hostname_isequal(cache_get_name(crecp), name)) hostname_isequal(cache_get_name(crecp), name))
skipping to change at line 753 skipping to change at line 892
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;
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;
else else
{ {
/* 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. All the reverse entries are at the also free anything which has expired. All the reverse entries are at the
start of the hash chain, so we can give up when we find the first start of the hash chain, so we can give up when we find the first
non-REVERSE one. */ non-REVERSE one. */
int i; int i;
struct crec **up, **chainp = &ans; struct crec **up, **chainp = &ans;
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 && (crecp->flags & F_REVERSE);
crecp = crecp->hash_next) crecp = crecp->hash_next)
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))
{ {
*chainp = crecp; *chainp = crecp;
chainp = &crecp->next; chainp = &crecp->next;
} }
else else
{ {
cache_unlink(crecp); cache_unlink(crecp);
cache_link(crecp); cache_link(crecp);
skipping to change at line 812 skipping to change at line 947
cache_free(crecp); cache_free(crecp);
} }
} }
*chainp = cache_head; *chainp = cache_head;
} }
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 addrle
{ n,
struct crec *crec;
struct cname *a;
for (a = daemon->cnames; a; a = a->next)
if (a->alias[1] != '*' &&
hostname_isequal(cache_get_name(target), a->target) &&
(crec = whine_malloc(SIZEOF_POINTER_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;
next_uid(target);
crec->addr.cname.uid = target->uid;
crec->uid = UID_NONE;
cache_hash(crec);
make_non_terminals(crec);
add_hosts_cname(crec); /* handle chains */
}
}
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
en,
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
the array rhash, hashed on address. Note that rhash and the values the array rhash, hashed on address. Note that rhash and the values
in ->next are only valid whilst reading hosts files: the buckets are in ->next are only valid whilst reading hosts files: the buckets are
then freed, and the ->next pointer used for other things. then freed, and the ->next pointer used for other things.
Only insert each unique address once into this hashing structure. Only insert each unique address once into this hashing structure.
skipping to change at line 885 skipping to change at line 992
*/ */
if (rhash) if (rhash)
{ {
/* hash address */ /* hash address */
for (j = 0, i = 0; i < addrlen; i++) for (j = 0, i = 0; i < addrlen; i++)
j = (j*2 +((unsigned char *)addr)[i]) % hashsz; j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
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;
} }
/* maintain address hash chain, insert new unique address */ /* maintain address hash chain, insert new unique address */
if (!lookup) if (!lookup)
{ {
cache->next = rhash[j]; cache->next = rhash[j];
rhash[j] = cache; rhash[j] = cache;
skipping to change at line 907 skipping to change at line 1014
} }
else else
{ {
/* incremental read, lookup in cache */ /* incremental read, lookup in cache */
lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6 )); lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6 ));
if (lookup && lookup->flags & F_HOSTS) if (lookup && lookup->flags & F_HOSTS)
cache->flags &= ~F_REVERSE; cache->flags &= ~F_REVERSE;
} }
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); 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)
{ {
int c, nl = 0; int c, nl = 0;
while (1) while (1)
{ {
if ((c = getc(f)) == '#') if ((c = getc(f)) == '#')
while (c != '\n' && c != EOF) while (c != '\n' && c != EOF)
skipping to change at line 936 skipping to change at line 1039
if (c == EOF) if (c == EOF)
return 1; return 1;
if (!isspace(c)) if (!isspace(c))
{ {
ungetc(c, f); ungetc(c, f);
return nl; return nl;
} }
if (c == '\n') if (c == '\n')
nl = 1; nl++;
} }
} }
static int gettok(FILE *f, char *token) static int gettok(FILE *f, char *token)
{ {
int c, count = 0; int c, count = 0;
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 == '#')
{ {
ungetc(c, f); ungetc(c, f);
return eatspace(f); return eatspace(f);
} }
if (count < (MAXDNAME - 1)) if (count < (MAXDNAME - 1))
{ {
token[count++] = c; token[count++] = c;
token[count] = 0; token[count] = 0;
} }
} }
} }
int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr ec **rhash, int hashsz) int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr ec **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;
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)
{ {
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerr or(errno)); my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerr or(errno));
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;
} }
addr_count++; addr_count++;
/* rehash every 1000 names. */ /* rehash every 1000 names. */
if (rhash && ((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;
} }
while (atnl == 0) while (atnl == 0)
{ {
struct crec *cache; struct crec *cache;
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, '.');
if ((canon = canonicalise(token, &nomem))) if ((canon = canonicalise(token, &nomem)))
{ {
/* 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_BARE_CREC + strlen(canon) + 2 + st rlen(domain_suffix)))) (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + st rlen(domain_suffix))))
{ {
skipping to change at line 1054 skipping to change at line 1154
cache->ttd = daemon->local_ttl; 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++;
} }
free(canon); free(canon);
} }
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);
if (rhash) if (rhash)
rehash(name_count); 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;
} }
void cache_reload(void) void cache_reload(void)
{ {
struct crec *cache, **up, *tmp; struct crec *cache, **up, *tmp;
int revhashsz, i, total_size = daemon->cachesize; int revhashsz, i, total_size = daemon->cachesize;
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 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
daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0; daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 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))
{ {
*up = cache->hash_next; *up = cache->hash_next;
free(cache); free(cache);
} }
else if (!(cache->flags & F_DHCP)) else if (!(cache->flags & F_DHCP))
{ {
*up = cache->hash_next; *up = cache->hash_next;
if (cache->flags & F_BIGNAME) if (cache->flags & F_BIGNAME)
{ {
cache->name.bname->next = big_free; cache->name.bname->next = big_free;
big_free = cache->name.bname; big_free = cache->name.bname;
} }
cache->flags = 0; cache->flags = 0;
} }
else else
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 (a->alias[1] != '*' && ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
hostname_isequal(a->target, intr->name) && {
((cache = whine_malloc(SIZEOF_POINTER_CREC)))) cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
{ cache->ttd = a->ttl;
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; cache->name.namep = a->alias;
cache->ttd = a->ttl; cache->addr.cname.target.name = a->target;
cache->name.namep = a->alias; cache->addr.cname.is_name_ptr = 1;
cache->addr.cname.target.int_name = intr; cache->uid = UID_NONE;
cache->addr.cname.uid = SRC_INTERFACE; cache_hash(cache);
cache->uid = UID_NONE; make_non_terminals(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_POINTER_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;
cache->ttd = daemon->local_ttl; cache->ttd = daemon->local_ttl;
cache->name.namep = ds->name; cache->name.namep = ds->name;
cache->addr.ds.keylen = ds->digestlen; cache->addr.ds.keylen = ds->digestlen;
skipping to change at line 1154 skipping to change at line 1257
/* 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 *);
/* we overwrote the buffer... */ /* we overwrote the buffer... */
daemon->srv_save = NULL; daemon->srv_save = NULL;
/* Do host_records in config. */ /* Do host_records in config. */
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_POINTER_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_CO NFIG, (struct crec **)daemon->packet, revhashsz); add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CON FIG, (struct crec **)daemon->packet, revhashsz);
} }
#ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && if ((hr->flags & HR_6) &&
(cache = whine_malloc(SIZEOF_POINTER_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_C ONFIG, (struct crec **)daemon->packet, revhashsz);
} }
#endif
} }
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts) if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
{ {
if (daemon->cachesize > 0) if (daemon->cachesize > 0)
my_syslog(LOG_INFO, _("cleared cache")); my_syslog(LOG_INFO, _("cleared cache"));
} }
else else
{ {
if (!option_bool(OPT_NO_HOSTS)) if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct cre c **)daemon->packet, revhashsz); total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct cre c **)daemon->packet, revhashsz);
daemon->addn_hosts = expand_filelist(daemon->addn_hosts); daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
for (ah = daemon->addn_hosts; ah; ah = ah->next) for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE)) if (!(ah->flags & AH_INACTIVE))
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct c rec **)daemon->packet, revhashsz); total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct c rec **)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, revh ashsz); set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revh ashsz);
#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)
{ {
struct crec *crecp = NULL; struct crec *crecp = NULL;
struct in_addr ret; struct in_addr ret;
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);
ret.s_addr = 0; ret.s_addr = 0;
return ret; return ret;
} }
void cache_unhash_dhcp(void) void cache_unhash_dhcp(void)
{ {
struct crec *cache, **up; struct crec *cache, **up;
skipping to change at line 1229 skipping to change at line 1364
if (cache->flags & F_DHCP) if (cache->flags & F_DHCP)
{ {
*up = cache->hash_next; *up = cache->hash_next;
cache->next = dhcp_spare; cache->next = dhcp_spare;
dhcp_spare = cache; dhcp_spare = cache;
} }
else else
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 (a->alias[1] != '*' &&
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_POINTER_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;
next_uid(target);
aliasc->addr.cname.uid = target->uid;
aliasc->uid = UID_NONE;
cache_hash(aliasc);
make_non_terminals(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);
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 | F_CONFIG)) 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,
_("%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), NULL, NULL); cache_scan_free(host_name, NULL, C_IN, 0, crec->flags & (flags | F_CNAM E | F_FORWARD), NULL, NULL);
/* scan_free deletes all addresses associated with name */ /* scan_free deletes all addresses associated with name */
break; break;
} }
} }
/* if in hosts, don't need DHCP record */ /* if in hosts, don't need DHCP record */
if (in_hosts) if (in_hosts)
return; return;
/* 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"),
host_name, daemon->addrbuff, host_name, daemon->addrbuff,
record_source(fail_crec->uid), daemon->namebuff); record_source(fail_crec->uid), daemon->namebuff);
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, NULL, NULL); cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, N ULL, NULL);
} }
} }
else else
flags |= F_REVERSE; flags |= F_REVERSE;
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_POINTER_CREC); crec = whine_malloc(SIZEOF_POINTER_CREC);
if (crec) /* malloc may fail */ if (crec) /* malloc may fail */
{ {
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD; crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
if (ttd == 0) if (ttd == 0)
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 = UID_NONE; crec->uid = UID_NONE;
cache_hash(crec); cache_hash(crec);
make_non_terminals(crec); make_non_terminals(crec);
add_dhcp_cname(crec, ttd);
} }
} }
#endif #endif
/* Called when we put a local or DHCP name into the cache. /* Called when we put a local or DHCP name into the cache.
Creates empty cache entries for subnames (ie, Creates empty cache entries for subnames (ie,
for three.two.one, for two.one and one), without for three.two.one, for two.one and one), without
F_IPV4 or F_IPV6 or F_CNAME set. These convert F_IPV4 or F_IPV6 or F_CNAME set. These convert
NXDOMAIN answers to NoData ones. */ NXDOMAIN answers to NoData ones. */
static void make_non_terminals(struct crec *source) static void make_non_terminals(struct crec *source)
skipping to change at line 1379 skipping to change at line 1477
entry and vice-versa for HOSTS and CONFIG. This ensures that entry and vice-versa for HOSTS and CONFIG. This ensures that
non-terminals from DHCP go when we reload DHCP and non-terminals from DHCP go when we reload DHCP and
for HOSTS/CONFIG when we re-read. */ for HOSTS/CONFIG when we re-read. */
for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp) for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
{ {
tmp = crecp->hash_next; tmp = crecp->hash_next;
if (!is_outdated_cname_pointer(crecp) && if (!is_outdated_cname_pointer(crecp) &&
(crecp->flags & F_FORWARD) && (crecp->flags & F_FORWARD) &&
(crecp->flags & type) && (crecp->flags & type) &&
!(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) && !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS)) &&
hostname_isequal(name, cache_get_name(crecp))) hostname_isequal(name, cache_get_name(crecp)))
{ {
*up = crecp->hash_next; *up = crecp->hash_next;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (type & F_DHCP) if (type & F_DHCP)
{ {
crecp->next = dhcp_spare; crecp->next = dhcp_spare;
dhcp_spare = crecp; dhcp_spare = crecp;
} }
else else
skipping to change at line 1436 skipping to change at line 1534
{ {
crecp = dhcp_spare; crecp = dhcp_spare;
dhcp_spare = dhcp_spare->next; dhcp_spare = dhcp_spare->next;
} }
else else
#endif #endif
crecp = whine_malloc(SIZEOF_POINTER_CREC); crecp = whine_malloc(SIZEOF_POINTER_CREC);
if (crecp) if (crecp)
{ {
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE); 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->ttd = source->ttd;
crecp->name.namep = name; crecp->name.namep = name;
cache_hash(crecp); cache_hash(crecp);
} }
} }
} }
#ifndef NO_ID #ifndef NO_ID
int cache_make_stat(struct txt_record *t) int cache_make_stat(struct txt_record *t)
skipping to change at line 1568 skipping to change at line 1666
struct server *serv, *serv1; struct server *serv, *serv1;
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, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daem on->metrics[METRIC_DNS_CACHE_INSERTED]); daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daem on->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->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC _DNS_LOCAL_ANSWERED]); 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->metrics[M ETRIC_DNS_AUTH_ANSWERED]); my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[M ETRIC_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)
serv->flags &= ~SERV_COUNTED; serv->flags &= ~SERV_COUNTED;
for (serv = daemon->servers; serv; serv = serv->next) for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags & if (!(serv->flags &
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND))) (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
{ {
int port; int port;
skipping to change at line 1612 skipping to change at line 1709
for (cache = hash_table[i]; cache; cache = cache->hash_next) for (cache = hash_table[i]; cache; cache = cache->hash_next)
{ {
char *t = " "; char *t = " ";
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_nam e(cache); char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_nam e(cache);
*a = 0; *a = 0;
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
n = "<Root>"; n = "<Root>";
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.srv
port);
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)
{ {
if (!(cache->flags & F_NEG)) if (!(cache->flags & F_NEG))
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag, sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
cache->addr.ds.algo, cache->addr.ds.digest); cache->addr.ds.algo, cache->addr.ds.digest);
} }
else if (cache->flags & F_DNSKEY) else if (cache->flags & F_DNSKEY)
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag, sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
cache->addr.key.algo, cache->addr.key.flags); cache->addr.key.algo, cache->addr.key.flags);
#endif #endif
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD)) 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)
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)
t = "4"; t = "4";
else if (cache->flags & F_IPV6) else if (cache->flags & F_IPV6)
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";
else if (cache->flags & F_DNSKEY) else if (cache->flags & F_DNSKEY)
t = "K"; t = "K";
#endif #endif
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t, 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" : " ",
skipping to change at line 1744 skipping to change at line 1852
if (types) if (types)
sprintf(buff, "<%s>", types); sprintf(buff, "<%s>", types);
else else
sprintf(buff, "type=%d", type); 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";
if (!option_bool(OPT_LOG)) if (!option_bool(OPT_LOG))
return; return;
name = sanitise(name); name = sanitise(name);
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->lo g.digest);
else if (flags & F_RCODE) else if (flags & F_RCODE)
{ {
unsigned int rcode = addr->addr.rcode.rcode; unsigned int rcode = addr->log.rcode;
if (rcode == SERVFAIL) if (rcode == SERVFAIL)
dest = "SERVFAIL"; dest = "SERVFAIL";
else if (rcode == REFUSED) else if (rcode == REFUSED)
dest = "REFUSED"; dest = "REFUSED";
else if (rcode == NOTIMP) else if (rcode == NOTIMP)
dest = "not implemented"; dest = "not implemented";
else else
sprintf(daemon->addrbuff, "%u", rcode); sprintf(daemon->addrbuff, "%u", rcode);
} }
else else
{ inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
#ifdef HAVE_IPV6 addr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
addr, daemon->addrbuff, ADDRSTRLEN);
#else
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
#endif
}
} }
else else
dest = arg; dest = arg;
if (flags & F_REVERSE) if (flags & F_REVERSE)
{ {
dest = name; dest = name;
name = daemon->addrbuff; name = daemon->addrbuff;
} }
skipping to change at line 1806 skipping to change at line 1909
if (flags & F_IPV4) if (flags & F_IPV4)
dest = "NODATA-IPv4"; dest = "NODATA-IPv4";
else if (flags & F_IPV6) else if (flags & F_IPV6)
dest = "NODATA-IPv6"; dest = "NODATA-IPv6";
else else
dest = "NODATA"; dest = "NODATA";
} }
} }
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;
if (flags & F_CONFIG) if (flags & F_CONFIG)
source = "config"; source = "config";
else if (flags & F_DHCP) else if (flags & F_DHCP)
source = "DHCP"; source = "DHCP";
else if (flags & F_HOSTS) else if (flags & F_HOSTS)
source = arg; source = arg;
else if (flags & F_UPSTREAM) else if (flags & F_UPSTREAM)
 End of changes. 104 change blocks. 
208 lines changed or deleted 336 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)