]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
1 /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 static struct crec
*cache_head
= NULL
, *cache_tail
= NULL
, **hash_table
= NULL
;
21 static struct crec
*dhcp_spare
= NULL
;
23 static struct crec
*new_chain
= NULL
;
24 static int cache_inserted
= 0, cache_live_freed
= 0, insert_error
;
25 static union bigname
*big_free
= NULL
;
26 static int bignames_left
, hash_size
;
29 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
32 const char * const name
;
68 static void cache_free(struct crec
*crecp
);
69 static void cache_unlink(struct crec
*crecp
);
70 static void cache_link(struct crec
*crecp
);
71 static void rehash(int size
);
72 static void cache_hash(struct crec
*crecp
);
79 bignames_left
= daemon
->cachesize
/10;
81 if (daemon
->cachesize
> 0)
83 crecp
= safe_malloc(daemon
->cachesize
*sizeof(struct crec
));
85 for (i
=0; i
< daemon
->cachesize
; i
++, crecp
++)
93 /* create initial hash table*/
94 rehash(daemon
->cachesize
);
97 /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
98 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
99 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
101 static void rehash(int size
)
103 struct crec
**new, **old
, *p
, *tmp
;
104 int i
, new_size
, old_size
;
106 /* hash_size is a power of two. */
107 for (new_size
= 64; new_size
< size
/10; new_size
= new_size
<< 1);
109 /* must succeed in getting first instance, failure later is non-fatal */
111 new = safe_malloc(new_size
* sizeof(struct crec
*));
112 else if (new_size
<= hash_size
|| !(new = whine_malloc(new_size
* sizeof(struct crec
*))))
115 for(i
= 0; i
< new_size
; i
++)
119 old_size
= hash_size
;
121 hash_size
= new_size
;
125 for (i
= 0; i
< old_size
; i
++)
126 for (p
= old
[i
]; p
; p
= tmp
)
135 static struct crec
**hash_bucket(char *name
)
137 unsigned int c
, val
= 017465; /* Barker code - minimum self-correlation in cyclic shift */
138 const unsigned char *mix_tab
= (const unsigned char*)typestr
;
140 while((c
= (unsigned char) *name
++))
142 /* don't use tolower and friends here - they may be messed up by LOCALE */
143 if (c
>= 'A' && c
<= 'Z')
145 val
= ((val
<< 7) | (val
>> (32 - 7))) + (mix_tab
[(val
+ c
) & 0x3F] ^ c
);
148 /* hash_size is a power of two */
149 return hash_table
+ ((val
^ (val
>> 16)) & (hash_size
- 1));
152 static void cache_hash(struct crec
*crecp
)
154 /* maintain an invariant that all entries with F_REVERSE set
155 are at the start of the hash-chain and all non-reverse
156 immortal entries are at the end of the hash-chain.
157 This allows reverse searches and garbage collection to be optimised */
159 struct crec
**up
= hash_bucket(cache_get_name(crecp
));
161 if (!(crecp
->flags
& F_REVERSE
))
163 while (*up
&& ((*up
)->flags
& F_REVERSE
))
164 up
= &((*up
)->hash_next
);
166 if (crecp
->flags
& F_IMMORTAL
)
167 while (*up
&& !((*up
)->flags
& F_IMMORTAL
))
168 up
= &((*up
)->hash_next
);
170 crecp
->hash_next
= *up
;
174 static void cache_free(struct crec
*crecp
)
176 crecp
->flags
&= ~F_FORWARD
;
177 crecp
->flags
&= ~F_REVERSE
;
178 crecp
->uid
= uid
++; /* invalidate CNAMES pointing to this. */
184 cache_tail
->next
= crecp
;
187 crecp
->prev
= cache_tail
;
191 /* retrieve big name for further use. */
192 if (crecp
->flags
& F_BIGNAME
)
194 crecp
->name
.bname
->next
= big_free
;
195 big_free
= crecp
->name
.bname
;
196 crecp
->flags
&= ~F_BIGNAME
;
199 else if (crecp
->flags
& (F_DNSKEY
| F_DS
))
200 blockdata_free(crecp
->addr
.key
.keydata
);
204 /* insert a new cache entry at the head of the list (youngest entry) */
205 static void cache_link(struct crec
*crecp
)
207 if (cache_head
) /* check needed for init code */
208 cache_head
->prev
= crecp
;
209 crecp
->next
= cache_head
;
216 /* remove an arbitrary cache entry for promotion */
217 static void cache_unlink (struct crec
*crecp
)
220 crecp
->prev
->next
= crecp
->next
;
222 cache_head
= crecp
->next
;
225 crecp
->next
->prev
= crecp
->prev
;
227 cache_tail
= crecp
->prev
;
230 char *cache_get_name(struct crec
*crecp
)
232 if (crecp
->flags
& F_BIGNAME
)
233 return crecp
->name
.bname
->name
;
234 else if (crecp
->flags
& F_NAMEP
)
235 return crecp
->name
.namep
;
237 return crecp
->name
.sname
;
240 char *cache_get_cname_target(struct crec
*crecp
)
242 if (crecp
->addr
.cname
.uid
!= -1)
243 return cache_get_name(crecp
->addr
.cname
.target
.cache
);
245 return crecp
->addr
.cname
.target
.int_name
->name
;
250 struct crec
*cache_enumerate(int init
)
253 static struct crec
*cache
;
260 else if (cache
&& cache
->hash_next
)
261 cache
= cache
->hash_next
;
265 while (bucket
< hash_size
)
266 if ((cache
= hash_table
[bucket
++]))
273 static int is_outdated_cname_pointer(struct crec
*crecp
)
275 if (!(crecp
->flags
& F_CNAME
) || crecp
->addr
.cname
.uid
== -1)
278 /* NB. record may be reused as DS or DNSKEY, where uid is
279 overloaded for something completely different */
280 if (crecp
->addr
.cname
.target
.cache
&&
281 (crecp
->addr
.cname
.target
.cache
->flags
& (F_IPV4
| F_IPV6
| F_CNAME
)) &&
282 crecp
->addr
.cname
.uid
== crecp
->addr
.cname
.target
.cache
->uid
)
288 static int is_expired(time_t now
, struct crec
*crecp
)
290 if (crecp
->flags
& F_IMMORTAL
)
293 if (difftime(now
, crecp
->ttd
) < 0)
299 static int cache_scan_free(char *name
, struct all_addr
*addr
, time_t now
, unsigned short flags
)
301 /* Scan and remove old entries.
302 If (flags & F_FORWARD) then remove any forward entries for name and any expired
303 entries but only in the same hash bucket as name.
304 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
305 entries in the whole cache.
306 If (flags == 0) remove any expired entries in the whole cache.
308 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
309 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
311 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
312 so that when we hit an entry which isn't reverse and is immortal, we're done. */
314 struct crec
*crecp
, **up
;
316 if (flags
& F_FORWARD
)
318 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= crecp
->hash_next
)
320 if (is_expired(now
, crecp
) || is_outdated_cname_pointer(crecp
))
322 *up
= crecp
->hash_next
;
323 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
331 if ((crecp
->flags
& F_FORWARD
) && hostname_isequal(cache_get_name(crecp
), name
))
333 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
334 if ((flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) ||
335 (((crecp
->flags
| flags
) & F_CNAME
) && !(crecp
->flags
& (F_DNSKEY
| F_DS
))))
337 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
339 *up
= crecp
->hash_next
;
346 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
347 type-covered sensitive for RRSIG */
348 if ((flags
& (F_DNSKEY
| F_DS
)) &&
349 (flags
& (F_DNSKEY
| F_DS
)) == (crecp
->flags
& (F_DNSKEY
| F_DS
)) &&
350 crecp
->uid
== addr
->addr
.dnssec
.class &&
351 (!((flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
)) ||
352 crecp
->addr
.sig
.type_covered
== addr
->addr
.dnssec
.type
))
354 if (crecp
->flags
& F_CONFIG
)
356 *up
= crecp
->hash_next
;
363 up
= &crecp
->hash_next
;
370 int addrlen
= (flags
& F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
372 int addrlen
= INADDRSZ
;
374 for (i
= 0; i
< hash_size
; i
++)
375 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
376 crecp
&& ((crecp
->flags
& F_REVERSE
) || !(crecp
->flags
& F_IMMORTAL
));
377 crecp
= crecp
->hash_next
)
378 if (is_expired(now
, crecp
))
380 *up
= crecp
->hash_next
;
381 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
387 else if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)) &&
388 (flags
& crecp
->flags
& F_REVERSE
) &&
389 (flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
390 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
392 *up
= crecp
->hash_next
;
397 up
= &crecp
->hash_next
;
403 /* Note: The normal calling sequence is
408 but an abort can cause the cache_end_insert to be missed
409 in which can the next cache_start_insert cleans things up. */
411 void cache_start_insert(void)
413 /* Free any entries which didn't get committed during the last
418 struct crec
*tmp
= new_chain
->next
;
419 cache_free(new_chain
);
426 struct crec
*cache_insert(char *name
, struct all_addr
*addr
,
427 time_t now
, unsigned long ttl
, unsigned short flags
)
430 union bigname
*big_name
= NULL
;
431 int freed_all
= flags
& F_REVERSE
;
434 if (daemon
->max_cache_ttl
!= 0 && daemon
->max_cache_ttl
< ttl
)
435 ttl
= daemon
->max_cache_ttl
;
437 /* Don't log keys here, done elsewhere */
438 if (flags
& (F_IPV4
| F_IPV6
| F_CNAME
))
439 log_query(flags
| F_UPSTREAM
, name
, addr
, NULL
);
441 /* if previous insertion failed give up now. */
445 /* First remove any expired entries and entries for the name/address we
446 are currently inserting. Fail is we attempt to delete a name from
447 /etc/hosts or DHCP. */
448 if (!cache_scan_free(name
, addr
, now
, flags
))
454 /* Now get a cache entry from the end of the LRU list */
456 if (!(new = cache_tail
)) /* no entries left - cache is too small, bail */
462 /* End of LRU list is still in use: if we didn't scan all the hash
463 chains for expired entries do that now. If we already tried that
464 then it's time to start spilling things. */
466 if (new->flags
& (F_FORWARD
| F_REVERSE
))
468 /* If free_avail set, we believe that an entry has been freed.
469 Bugs have been known to make this not true, resulting in
470 a tight loop here. If that happens, abandon the
471 insert. Once in this state, all inserts will probably fail. */
480 free_avail
= 1; /* Must be free space now. */
481 cache_scan_free(cache_get_name(new), &new->addr
.addr
, now
, new->flags
);
486 cache_scan_free(NULL
, NULL
, now
, 0);
492 /* Check if we need to and can allocate extra memory for a long name.
493 If that fails, give up now. */
494 if (name
&& (strlen(name
) > SMALLDNAME
-1))
499 big_free
= big_free
->next
;
501 else if (!bignames_left
||
502 !(big_name
= (union bigname
*)whine_malloc(sizeof(union bigname
))))
512 /* Got the rest: finally grab entry. */
520 new->name
.bname
= big_name
;
521 new->flags
|= F_BIGNAME
;
525 strcpy(cache_get_name(new), name
);
527 *cache_get_name(new) = 0;
530 new->addr
.addr
= *addr
;
532 new->ttd
= now
+ (time_t)ttl
;
533 new->next
= new_chain
;
539 /* after end of insertion, commit the new entries */
540 void cache_end_insert(void)
547 struct crec
*tmp
= new_chain
->next
;
548 /* drop CNAMEs which didn't find a target. */
549 if (is_outdated_cname_pointer(new_chain
))
550 cache_free(new_chain
);
553 cache_hash(new_chain
);
554 cache_link(new_chain
);
562 struct crec
*cache_find_by_name(struct crec
*crecp
, char *name
, time_t now
, unsigned short prot
)
566 if (crecp
) /* iterating */
570 /* first search, look for relevant entries and push to top of list
571 also free anything which has expired */
572 struct crec
*next
, **up
, **insert
= NULL
, **chainp
= &ans
;
573 unsigned short ins_flags
= 0;
575 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= next
)
577 next
= crecp
->hash_next
;
579 if (!is_expired(now
, crecp
) && !is_outdated_cname_pointer(crecp
))
581 if ((crecp
->flags
& F_FORWARD
) &&
583 ((crecp
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
585 (crecp
->flags
& prot
) &&
586 hostname_isequal(cache_get_name(crecp
), name
))
588 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
591 chainp
= &crecp
->next
;
599 /* Move all but the first entry up the hash chain
600 this implements round-robin.
601 Make sure that re-ordering doesn't break the hash-chain
604 if (insert
&& (crecp
->flags
& (F_REVERSE
| F_IMMORTAL
)) == ins_flags
)
606 *up
= crecp
->hash_next
;
607 crecp
->hash_next
= *insert
;
609 insert
= &crecp
->hash_next
;
616 ins_flags
= crecp
->flags
& (F_REVERSE
| F_IMMORTAL
);
618 up
= &crecp
->hash_next
;
622 /* case : not expired, incorrect entry. */
623 up
= &crecp
->hash_next
;
627 /* expired entry, free it */
628 *up
= crecp
->hash_next
;
629 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
637 *chainp
= cache_head
;
641 (ans
->flags
& F_FORWARD
) &&
643 ((ans
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
645 (ans
->flags
& prot
) &&
646 hostname_isequal(cache_get_name(ans
), name
))
652 struct crec
*cache_find_by_addr(struct crec
*crecp
, struct all_addr
*addr
,
653 time_t now
, unsigned short prot
)
657 int addrlen
= (prot
== F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
659 int addrlen
= INADDRSZ
;
662 if (crecp
) /* iterating */
666 /* first search, look for relevant entries and push to top of list
667 also free anything which has expired. All the reverse entries are at the
668 start of the hash chain, so we can give up when we find the first
671 struct crec
**up
, **chainp
= &ans
;
673 for (i
=0; i
<hash_size
; i
++)
674 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
675 crecp
&& (crecp
->flags
& F_REVERSE
);
676 crecp
= crecp
->hash_next
)
677 if (!is_expired(now
, crecp
))
679 if ((crecp
->flags
& prot
) &&
680 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
682 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
685 chainp
= &crecp
->next
;
693 up
= &crecp
->hash_next
;
697 *up
= crecp
->hash_next
;
698 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
705 *chainp
= cache_head
;
709 (ans
->flags
& F_REVERSE
) &&
710 (ans
->flags
& prot
) &&
711 memcmp(&ans
->addr
.addr
, addr
, addrlen
) == 0)
717 static void add_hosts_cname(struct crec
*target
)
722 for (a
= daemon
->cnames
; a
; a
= a
->next
)
723 if (hostname_isequal(cache_get_name(target
), a
->target
) &&
724 (crec
= whine_malloc(sizeof(struct crec
))))
726 crec
->flags
= F_FORWARD
| F_IMMORTAL
| F_NAMEP
| F_CONFIG
| F_CNAME
;
727 crec
->name
.namep
= a
->alias
;
728 crec
->addr
.cname
.target
.cache
= target
;
729 crec
->addr
.cname
.uid
= target
->uid
;
731 add_hosts_cname(crec
); /* handle chains */
735 static void add_hosts_entry(struct crec
*cache
, struct all_addr
*addr
, int addrlen
,
736 int index
, struct crec
**rhash
, int hashsz
)
738 struct crec
*lookup
= cache_find_by_name(NULL
, cache_get_name(cache
), 0, cache
->flags
& (F_IPV4
| F_IPV6
));
739 int i
, nameexists
= 0;
742 /* Remove duplicates in hosts files. */
743 if (lookup
&& (lookup
->flags
& F_HOSTS
))
746 if (memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
753 /* Ensure there is only one address -> name mapping (first one trumps)
754 We do this by steam here, The entries are kept in hash chains, linked
755 by ->next (which is unused at this point) held in hash buckets in
756 the array rhash, hashed on address. Note that rhash and the values
757 in ->next are only valid whilst reading hosts files: the buckets are
758 then freed, and the ->next pointer used for other things.
760 Only insert each unique address once into this hashing structure.
762 This complexity avoids O(n^2) divergent CPU use whilst reading
763 large (10000 entry) hosts files. */
766 for (j
= 0, i
= 0; i
< addrlen
; i
++)
767 j
= (j
*2 +((unsigned char *)addr
)[i
]) % hashsz
;
769 for (lookup
= rhash
[j
]; lookup
; lookup
= lookup
->next
)
770 if ((lookup
->flags
& cache
->flags
& (F_IPV4
| F_IPV6
)) &&
771 memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
773 cache
->flags
&= ~F_REVERSE
;
777 /* maintain address hash chain, insert new unique address */
780 cache
->next
= rhash
[j
];
785 memcpy(&cache
->addr
.addr
, addr
, addrlen
);
788 /* don't need to do alias stuff for second and subsequent addresses. */
790 add_hosts_cname(cache
);
793 static int eatspace(FILE *f
)
799 if ((c
= getc(f
)) == '#')
800 while (c
!= '\n' && c
!= EOF
)
817 static int gettok(FILE *f
, char *token
)
823 if ((c
= getc(f
)) == EOF
)
824 return (count
== 0) ? EOF
: 1;
826 if (isspace(c
) || c
== '#')
832 if (count
< (MAXDNAME
- 1))
840 static int read_hostsfile(char *filename
, int index
, int cache_size
, struct crec
**rhash
, int hashsz
)
842 FILE *f
= fopen(filename
, "r");
843 char *token
= daemon
->namebuff
, *domain_suffix
= NULL
;
844 int addr_count
= 0, name_count
= cache_size
, lineno
= 0;
845 unsigned short flags
= 0;
846 struct all_addr addr
;
847 int atnl
, addrlen
= 0;
851 my_syslog(LOG_ERR
, _("failed to load names from %s: %s"), filename
, strerror(errno
));
857 while ((atnl
= gettok(f
, token
)) != EOF
)
861 if (inet_pton(AF_INET
, token
, &addr
) > 0)
863 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
;
865 domain_suffix
= get_domain(addr
.addr
.addr4
);
868 else if (inet_pton(AF_INET6
, token
, &addr
) > 0)
870 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
;
872 domain_suffix
= get_domain6(&addr
.addr
.addr6
);
877 my_syslog(LOG_ERR
, _("bad address at %s line %d"), filename
, lineno
);
879 atnl
= gettok(f
, token
);
885 /* rehash every 1000 names. */
886 if ((name_count
- cache_size
) > 1000)
889 cache_size
= name_count
;
898 if ((atnl
= gettok(f
, token
)) == EOF
)
901 fqdn
= !!strchr(token
, '.');
903 if ((canon
= canonicalise(token
, &nomem
)))
905 /* If set, add a version of the name with a default domain appended */
906 if (option_bool(OPT_EXPAND
) && domain_suffix
&& !fqdn
&&
907 (cache
= whine_malloc(sizeof(struct crec
) +
908 strlen(canon
)+2+strlen(domain_suffix
)-SMALLDNAME
)))
910 strcpy(cache
->name
.sname
, canon
);
911 strcat(cache
->name
.sname
, ".");
912 strcat(cache
->name
.sname
, domain_suffix
);
913 cache
->flags
= flags
;
914 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
917 if ((cache
= whine_malloc(sizeof(struct crec
) + strlen(canon
)+1-SMALLDNAME
)))
919 strcpy(cache
->name
.sname
, canon
);
920 cache
->flags
= flags
;
921 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
928 my_syslog(LOG_ERR
, _("bad name at %s line %d"), filename
, lineno
);
935 my_syslog(LOG_INFO
, _("read %s - %d addresses"), filename
, addr_count
);
940 void cache_reload(void)
942 struct crec
*cache
, **up
, *tmp
;
943 int revhashsz
, i
, total_size
= daemon
->cachesize
;
944 struct hostsfile
*ah
;
945 struct host_record
*hr
;
946 struct name_list
*nl
;
948 struct interface_name
*intr
;
953 cache_inserted
= cache_live_freed
= 0;
955 for (i
=0; i
<hash_size
; i
++)
956 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= tmp
)
959 if (cache
->flags
& (F_DNSKEY
| F_DS
))
960 blockdata_free(cache
->addr
.key
.keydata
);
962 tmp
= cache
->hash_next
;
963 if (cache
->flags
& (F_HOSTS
| F_CONFIG
))
965 *up
= cache
->hash_next
;
968 else if (!(cache
->flags
& F_DHCP
))
970 *up
= cache
->hash_next
;
971 if (cache
->flags
& F_BIGNAME
)
973 cache
->name
.bname
->next
= big_free
;
974 big_free
= cache
->name
.bname
;
979 up
= &cache
->hash_next
;
982 /* Add CNAMEs to interface_names to the cache */
983 for (a
= daemon
->cnames
; a
; a
= a
->next
)
984 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
985 if (hostname_isequal(a
->target
, intr
->name
) &&
986 ((cache
= whine_malloc(sizeof(struct crec
)))))
988 cache
->flags
= F_FORWARD
| F_NAMEP
| F_CNAME
| F_IMMORTAL
| F_CONFIG
;
989 cache
->name
.namep
= a
->alias
;
990 cache
->addr
.cname
.target
.int_name
= intr
;
991 cache
->addr
.cname
.uid
= -1;
993 add_hosts_cname(cache
); /* handle chains */
997 for (key
= daemon
->dnskeys
; key
; key
= key
->next
)
998 if ((cache
= whine_malloc(sizeof(struct crec
))) &&
999 (cache
->addr
.key
.keydata
= blockdata_alloc(key
->key
, key
->keylen
)))
1001 cache
->flags
= F_FORWARD
| F_IMMORTAL
| F_DNSKEY
| F_CONFIG
| F_NAMEP
;
1002 cache
->name
.namep
= key
->name
;
1003 cache
->addr
.key
.keylen
= key
->keylen
;
1004 cache
->addr
.key
.algo
= key
->algo
;
1005 cache
->addr
.key
.flags
= key
->flags
;
1006 cache
->addr
.key
.keytag
= dnskey_keytag(key
->algo
, key
->flags
, (unsigned char *)key
->key
, key
->keylen
);
1007 cache
->uid
= key
->class;
1012 /* borrow the packet buffer for a temporary by-address hash */
1013 memset(daemon
->packet
, 0, daemon
->packet_buff_sz
);
1014 revhashsz
= daemon
->packet_buff_sz
/ sizeof(struct crec
*);
1015 /* we overwrote the buffer... */
1016 daemon
->srv_save
= NULL
;
1018 /* Do host_records in config. */
1019 for (hr
= daemon
->host_records
; hr
; hr
= hr
->next
)
1020 for (nl
= hr
->names
; nl
; nl
= nl
->next
)
1022 if (hr
->addr
.s_addr
!= 0 &&
1023 (cache
= whine_malloc(sizeof(struct crec
))))
1025 cache
->name
.namep
= nl
->name
;
1026 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_NAMEP
| F_CONFIG
;
1027 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr
, INADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1030 if (!IN6_IS_ADDR_UNSPECIFIED(&hr
->addr6
) &&
1031 (cache
= whine_malloc(sizeof(struct crec
))))
1033 cache
->name
.namep
= nl
->name
;
1034 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_NAMEP
| F_CONFIG
;
1035 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr6
, IN6ADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1040 if (option_bool(OPT_NO_HOSTS
) && !daemon
->addn_hosts
)
1042 if (daemon
->cachesize
> 0)
1043 my_syslog(LOG_INFO
, _("cleared cache"));
1047 if (!option_bool(OPT_NO_HOSTS
))
1048 total_size
= read_hostsfile(HOSTSFILE
, 0, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1050 daemon
->addn_hosts
= expand_filelist(daemon
->addn_hosts
);
1051 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1052 if (!(ah
->flags
& AH_INACTIVE
))
1053 total_size
= read_hostsfile(ah
->fname
, ah
->index
, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1057 struct in_addr
a_record_from_hosts(char *name
, time_t now
)
1059 struct crec
*crecp
= NULL
;
1062 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
1063 if (crecp
->flags
& F_HOSTS
)
1064 return *(struct in_addr
*)&crecp
->addr
;
1066 my_syslog(MS_DHCP
| LOG_WARNING
, _("No IPv4 address found for %s"), name
);
1072 void cache_unhash_dhcp(void)
1074 struct crec
*cache
, **up
;
1077 for (i
=0; i
<hash_size
; i
++)
1078 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1079 if (cache
->flags
& F_DHCP
)
1081 *up
= cache
->hash_next
;
1082 cache
->next
= dhcp_spare
;
1086 up
= &cache
->hash_next
;
1089 static void add_dhcp_cname(struct crec
*target
, time_t ttd
)
1091 struct crec
*aliasc
;
1094 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1095 if (hostname_isequal(cache_get_name(target
), a
->target
))
1097 if ((aliasc
= dhcp_spare
))
1098 dhcp_spare
= dhcp_spare
->next
;
1099 else /* need new one */
1100 aliasc
= whine_malloc(sizeof(struct crec
));
1104 aliasc
->flags
= F_FORWARD
| F_NAMEP
| F_DHCP
| F_CNAME
| F_CONFIG
;
1106 aliasc
->flags
|= F_IMMORTAL
;
1109 aliasc
->name
.namep
= a
->alias
;
1110 aliasc
->addr
.cname
.target
.cache
= target
;
1111 aliasc
->addr
.cname
.uid
= target
->uid
;
1113 add_dhcp_cname(aliasc
, ttd
);
1118 void cache_add_dhcp_entry(char *host_name
, int prot
,
1119 struct all_addr
*host_address
, time_t ttd
)
1121 struct crec
*crec
= NULL
, *fail_crec
= NULL
;
1122 unsigned short flags
= F_IPV4
;
1124 size_t addrlen
= sizeof(struct in_addr
);
1127 if (prot
== AF_INET6
)
1130 addrlen
= sizeof(struct in6_addr
);
1134 inet_ntop(prot
, host_address
, daemon
->addrbuff
, ADDRSTRLEN
);
1136 while ((crec
= cache_find_by_name(crec
, host_name
, 0, flags
| F_CNAME
)))
1138 /* check all addresses associated with name */
1139 if (crec
->flags
& (F_HOSTS
| F_CONFIG
))
1141 if (crec
->flags
& F_CNAME
)
1142 my_syslog(MS_DHCP
| LOG_WARNING
,
1143 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1144 host_name
, daemon
->addrbuff
);
1145 else if (memcmp(&crec
->addr
.addr
, host_address
, addrlen
) == 0)
1150 else if (!(crec
->flags
& F_DHCP
))
1152 cache_scan_free(host_name
, NULL
, 0, crec
->flags
& (flags
| F_CNAME
| F_FORWARD
));
1153 /* scan_free deletes all addresses associated with name */
1158 /* if in hosts, don't need DHCP record */
1162 /* Name in hosts, address doesn't match */
1165 inet_ntop(prot
, &fail_crec
->addr
.addr
, daemon
->namebuff
, MAXDNAME
);
1166 my_syslog(MS_DHCP
| LOG_WARNING
,
1167 _("not giving name %s to the DHCP lease of %s because "
1168 "the name exists in %s with address %s"),
1169 host_name
, daemon
->addrbuff
,
1170 record_source(fail_crec
->uid
), daemon
->namebuff
);
1174 if ((crec
= cache_find_by_addr(NULL
, (struct all_addr
*)host_address
, 0, flags
)))
1176 if (crec
->flags
& F_NEG
)
1179 cache_scan_free(NULL
, (struct all_addr
*)host_address
, 0, flags
);
1185 if ((crec
= dhcp_spare
))
1186 dhcp_spare
= dhcp_spare
->next
;
1187 else /* need new one */
1188 crec
= whine_malloc(sizeof(struct crec
));
1190 if (crec
) /* malloc may fail */
1192 crec
->flags
= flags
| F_NAMEP
| F_DHCP
| F_FORWARD
;
1194 crec
->flags
|= F_IMMORTAL
;
1197 crec
->addr
.addr
= *host_address
;
1198 crec
->name
.namep
= host_name
;
1202 add_dhcp_cname(crec
, ttd
);
1208 void dump_cache(time_t now
)
1210 struct server
*serv
, *serv1
;
1213 my_syslog(LOG_INFO
, _("time %lu"), (unsigned long)now
);
1214 my_syslog(LOG_INFO
, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1215 daemon
->cachesize
, cache_live_freed
, cache_inserted
);
1216 my_syslog(LOG_INFO
, _("queries forwarded %u, queries answered locally %u"),
1217 daemon
->queries_forwarded
, daemon
->local_answer
);
1219 my_syslog(LOG_INFO
, _("queries for authoritative zones %u"), daemon
->auth_answer
);
1225 /* sum counts from different records for same server */
1226 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1227 serv
->flags
&= ~SERV_COUNTED
;
1229 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1231 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)))
1234 unsigned int queries
= 0, failed_queries
= 0;
1235 for (serv1
= serv
; serv1
; serv1
= serv1
->next
)
1236 if (!(serv1
->flags
&
1237 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)) &&
1238 sockaddr_isequal(&serv
->addr
, &serv1
->addr
))
1240 serv1
->flags
|= SERV_COUNTED
;
1241 queries
+= serv1
->queries
;
1242 failed_queries
+= serv1
->failed_queries
;
1244 port
= prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
1245 my_syslog(LOG_INFO
, _("server %s#%d: queries sent %u, retried or failed %u"), daemon
->addrbuff
, port
, queries
, failed_queries
);
1248 if (option_bool(OPT_DEBUG
) || option_bool(OPT_LOG
))
1250 struct crec
*cache
;
1252 my_syslog(LOG_INFO
, "Host Address Flags Expires");
1254 for (i
=0; i
<hash_size
; i
++)
1255 for (cache
= hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1257 char *a
= daemon
->addrbuff
, *p
= daemon
->namebuff
, *n
= cache_get_name(cache
);
1259 if (strlen(n
) == 0 && !(cache
->flags
& F_REVERSE
))
1261 p
+= sprintf(p
, "%-40.40s ", n
);
1262 if ((cache
->flags
& F_CNAME
) && !is_outdated_cname_pointer(cache
))
1263 a
= cache_get_cname_target(cache
);
1265 else if (cache
->flags
& F_DS
)
1267 if (cache
->flags
& F_DNSKEY
)
1271 querystr("", tp
, cache
->addr
.sig
.type_covered
);
1272 a
= daemon
->addrbuff
;
1273 sprintf(a
, "%5u %3u %s", cache
->addr
.sig
.keytag
,
1274 cache
->addr
.sig
.algo
, tp
);
1278 a
= daemon
->addrbuff
;
1279 sprintf(a
, "%5u %3u %3u", cache
->addr
.ds
.keytag
,
1280 cache
->addr
.ds
.algo
, cache
->addr
.ds
.digest
);
1283 else if (cache
->flags
& F_DNSKEY
)
1285 a
= daemon
->addrbuff
;
1286 sprintf(a
, "%5u %3u %3u", cache
->addr
.key
.keytag
,
1287 cache
->addr
.key
.algo
, cache
->addr
.key
.flags
);
1290 else if (!(cache
->flags
& F_NEG
) || !(cache
->flags
& F_FORWARD
))
1292 a
= daemon
->addrbuff
;
1293 if (cache
->flags
& F_IPV4
)
1294 inet_ntop(AF_INET
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1296 else if (cache
->flags
& F_IPV6
)
1297 inet_ntop(AF_INET6
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1301 if (cache
->flags
& F_IPV4
)
1303 else if (cache
->flags
& F_IPV6
)
1305 else if (cache
->flags
& F_CNAME
)
1308 else if ((cache
->flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
))
1309 t
= "G"; /* DNSKEY and DS set -> RRISG */
1310 else if (cache
->flags
& F_DS
)
1312 else if (cache
->flags
& F_DNSKEY
)
1315 p
+= sprintf(p
, "%-30.30s %s%s%s%s%s%s%s%s%s ", a
, t
,
1316 cache
->flags
& F_FORWARD
? "F" : " ",
1317 cache
->flags
& F_REVERSE
? "R" : " ",
1318 cache
->flags
& F_IMMORTAL
? "I" : " ",
1319 cache
->flags
& F_DHCP
? "D" : " ",
1320 cache
->flags
& F_NEG
? "N" : " ",
1321 cache
->flags
& F_NXDOMAIN
? "X" : " ",
1322 cache
->flags
& F_HOSTS
? "H" : " ",
1323 cache
->flags
& F_DNSSECOK
? "V" : " ");
1324 #ifdef HAVE_BROKEN_RTC
1325 p
+= sprintf(p
, "%lu", cache
->flags
& F_IMMORTAL
? 0: (unsigned long)(cache
->ttd
- now
));
1327 p
+= sprintf(p
, "%s", cache
->flags
& F_IMMORTAL
? "\n" : ctime(&(cache
->ttd
)));
1328 /* ctime includes trailing \n - eat it */
1331 my_syslog(LOG_INFO
, daemon
->namebuff
);
1336 char *record_source(int index
)
1338 struct hostsfile
*ah
;
1343 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1344 if (ah
->index
== index
)
1350 void querystr(char *desc
, char *str
, unsigned short type
)
1354 sprintf(str
, "%s[type=%d]", desc
, type
);
1355 for (i
= 0; i
< (sizeof(typestr
)/sizeof(typestr
[0])); i
++)
1356 if (typestr
[i
].type
== type
)
1357 sprintf(str
,"%s[%s]", desc
, typestr
[i
].name
);
1360 void log_query(unsigned int flags
, char *name
, struct all_addr
*addr
, char *arg
)
1362 char *source
, *dest
= daemon
->addrbuff
;
1365 if (!option_bool(OPT_LOG
))
1370 if (flags
& F_KEYTAG
)
1371 sprintf(daemon
->addrbuff
, arg
, addr
->addr
.keytag
);
1375 inet_ntop(flags
& F_IPV4
? AF_INET
: AF_INET6
,
1376 addr
, daemon
->addrbuff
, ADDRSTRLEN
);
1378 strncpy(daemon
->addrbuff
, inet_ntoa(addr
->addr
.addr4
), ADDRSTRLEN
);
1385 if (flags
& F_REVERSE
)
1388 name
= daemon
->addrbuff
;
1393 if (flags
& F_NXDOMAIN
)
1396 dest
= "NXDOMAIN-IPv4";
1397 else if (flags
& F_IPV6
)
1398 dest
= "NXDOMAIN-IPv6";
1405 dest
= "NODATA-IPv4";
1406 else if (flags
& F_IPV6
)
1407 dest
= "NODATA-IPv6";
1412 else if (flags
& F_CNAME
)
1414 else if (flags
& F_RRNAME
)
1417 if (flags
& F_CONFIG
)
1419 else if (flags
& F_DHCP
)
1421 else if (flags
& F_HOSTS
)
1423 else if (flags
& F_UPSTREAM
)
1425 else if (flags
& F_SECSTAT
)
1426 source
= "validation";
1427 else if (flags
& F_AUTH
)
1429 else if (flags
& F_SERVER
)
1431 source
= "forwarded";
1434 else if (flags
& F_QUERY
)
1439 else if (flags
& F_DNSSEC
)
1447 if (strlen(name
) == 0)
1450 my_syslog(LOG_INFO
, "%s %s %s %s", source
, name
, verb
, dest
);