]>
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
;
175 static void cache_blockdata_free(struct crec
*crecp
)
177 if (crecp
->flags
& F_DNSKEY
)
179 if (crecp
->flags
& F_DS
)
180 blockdata_free(crecp
->addr
.sig
.keydata
);
182 blockdata_free(crecp
->addr
.key
.keydata
);
184 else if (crecp
->flags
& F_DS
)
185 blockdata_free(crecp
->addr
.ds
.keydata
);
189 static void cache_free(struct crec
*crecp
)
191 crecp
->flags
&= ~F_FORWARD
;
192 crecp
->flags
&= ~F_REVERSE
;
193 crecp
->uid
= uid
++; /* invalidate CNAMES pointing to this. */
199 cache_tail
->next
= crecp
;
202 crecp
->prev
= cache_tail
;
206 /* retrieve big name for further use. */
207 if (crecp
->flags
& F_BIGNAME
)
209 crecp
->name
.bname
->next
= big_free
;
210 big_free
= crecp
->name
.bname
;
211 crecp
->flags
&= ~F_BIGNAME
;
215 cache_blockdata_free(crecp
);
219 /* insert a new cache entry at the head of the list (youngest entry) */
220 static void cache_link(struct crec
*crecp
)
222 if (cache_head
) /* check needed for init code */
223 cache_head
->prev
= crecp
;
224 crecp
->next
= cache_head
;
231 /* remove an arbitrary cache entry for promotion */
232 static void cache_unlink (struct crec
*crecp
)
235 crecp
->prev
->next
= crecp
->next
;
237 cache_head
= crecp
->next
;
240 crecp
->next
->prev
= crecp
->prev
;
242 cache_tail
= crecp
->prev
;
245 char *cache_get_name(struct crec
*crecp
)
247 if (crecp
->flags
& F_BIGNAME
)
248 return crecp
->name
.bname
->name
;
249 else if (crecp
->flags
& F_NAMEP
)
250 return crecp
->name
.namep
;
252 return crecp
->name
.sname
;
255 char *cache_get_cname_target(struct crec
*crecp
)
257 if (crecp
->addr
.cname
.uid
!= -1)
258 return cache_get_name(crecp
->addr
.cname
.target
.cache
);
260 return crecp
->addr
.cname
.target
.int_name
->name
;
265 struct crec
*cache_enumerate(int init
)
268 static struct crec
*cache
;
275 else if (cache
&& cache
->hash_next
)
276 cache
= cache
->hash_next
;
280 while (bucket
< hash_size
)
281 if ((cache
= hash_table
[bucket
++]))
288 static int is_outdated_cname_pointer(struct crec
*crecp
)
290 if (!(crecp
->flags
& F_CNAME
) || crecp
->addr
.cname
.uid
== -1)
293 /* NB. record may be reused as DS or DNSKEY, where uid is
294 overloaded for something completely different */
295 if (crecp
->addr
.cname
.target
.cache
&&
296 (crecp
->addr
.cname
.target
.cache
->flags
& (F_IPV4
| F_IPV6
| F_CNAME
)) &&
297 crecp
->addr
.cname
.uid
== crecp
->addr
.cname
.target
.cache
->uid
)
303 static int is_expired(time_t now
, struct crec
*crecp
)
305 if (crecp
->flags
& F_IMMORTAL
)
308 if (difftime(now
, crecp
->ttd
) < 0)
314 static int cache_scan_free(char *name
, struct all_addr
*addr
, time_t now
, unsigned short flags
)
316 /* Scan and remove old entries.
317 If (flags & F_FORWARD) then remove any forward entries for name and any expired
318 entries but only in the same hash bucket as name.
319 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
320 entries in the whole cache.
321 If (flags == 0) remove any expired entries in the whole cache.
323 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
324 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
326 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
327 so that when we hit an entry which isn't reverse and is immortal, we're done. */
329 struct crec
*crecp
, **up
;
331 if (flags
& F_FORWARD
)
333 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= crecp
->hash_next
)
335 if (is_expired(now
, crecp
) || is_outdated_cname_pointer(crecp
))
337 *up
= crecp
->hash_next
;
338 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
346 if ((crecp
->flags
& F_FORWARD
) && hostname_isequal(cache_get_name(crecp
), name
))
348 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
349 if ((flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) ||
350 (((crecp
->flags
| flags
) & F_CNAME
) && !(crecp
->flags
& (F_DNSKEY
| F_DS
))))
352 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
354 *up
= crecp
->hash_next
;
361 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
362 type-covered sensitive for RRSIG */
363 if ((flags
& (F_DNSKEY
| F_DS
)) &&
364 (flags
& (F_DNSKEY
| F_DS
)) == (crecp
->flags
& (F_DNSKEY
| F_DS
)) &&
365 crecp
->uid
== addr
->addr
.dnssec
.class &&
366 (!((flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
)) ||
367 crecp
->addr
.sig
.type_covered
== addr
->addr
.dnssec
.type
))
369 if (crecp
->flags
& F_CONFIG
)
371 *up
= crecp
->hash_next
;
378 up
= &crecp
->hash_next
;
385 int addrlen
= (flags
& F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
387 int addrlen
= INADDRSZ
;
389 for (i
= 0; i
< hash_size
; i
++)
390 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
391 crecp
&& ((crecp
->flags
& F_REVERSE
) || !(crecp
->flags
& F_IMMORTAL
));
392 crecp
= crecp
->hash_next
)
393 if (is_expired(now
, crecp
))
395 *up
= crecp
->hash_next
;
396 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
402 else if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)) &&
403 (flags
& crecp
->flags
& F_REVERSE
) &&
404 (flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
405 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
407 *up
= crecp
->hash_next
;
412 up
= &crecp
->hash_next
;
418 /* Note: The normal calling sequence is
423 but an abort can cause the cache_end_insert to be missed
424 in which can the next cache_start_insert cleans things up. */
426 void cache_start_insert(void)
428 /* Free any entries which didn't get committed during the last
433 struct crec
*tmp
= new_chain
->next
;
434 cache_free(new_chain
);
441 struct crec
*cache_insert(char *name
, struct all_addr
*addr
,
442 time_t now
, unsigned long ttl
, unsigned short flags
)
445 union bigname
*big_name
= NULL
;
446 int freed_all
= flags
& F_REVERSE
;
449 if (daemon
->max_cache_ttl
!= 0 && daemon
->max_cache_ttl
< ttl
)
450 ttl
= daemon
->max_cache_ttl
;
452 /* Don't log keys here, done elsewhere */
453 if (flags
& (F_IPV4
| F_IPV6
| F_CNAME
))
454 log_query(flags
| F_UPSTREAM
, name
, addr
, NULL
);
456 /* if previous insertion failed give up now. */
460 /* First remove any expired entries and entries for the name/address we
461 are currently inserting. Fail is we attempt to delete a name from
462 /etc/hosts or DHCP. */
463 if (!cache_scan_free(name
, addr
, now
, flags
))
469 /* Now get a cache entry from the end of the LRU list */
471 if (!(new = cache_tail
)) /* no entries left - cache is too small, bail */
477 /* End of LRU list is still in use: if we didn't scan all the hash
478 chains for expired entries do that now. If we already tried that
479 then it's time to start spilling things. */
481 if (new->flags
& (F_FORWARD
| F_REVERSE
))
483 /* If free_avail set, we believe that an entry has been freed.
484 Bugs have been known to make this not true, resulting in
485 a tight loop here. If that happens, abandon the
486 insert. Once in this state, all inserts will probably fail. */
489 static int warned
= 0;
492 my_syslog(LOG_ERR
, _("Internal error in cache."));
501 struct all_addr free_addr
= new->addr
.addr
;;
504 /* For DNSSEC records, addr holds class and type_covered for RRSIG */
505 if (new->flags
& (F_DS
| F_DNSKEY
))
507 free_addr
.addr
.dnssec
.class = new->uid
;
508 if ((new->flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
))
509 free_addr
.addr
.dnssec
.type
= new->addr
.sig
.type_covered
;
513 free_avail
= 1; /* Must be free space now. */
514 cache_scan_free(cache_get_name(new), &free_addr
, now
, new->flags
);
519 cache_scan_free(NULL
, NULL
, now
, 0);
525 /* Check if we need to and can allocate extra memory for a long name.
526 If that fails, give up now, always succeed for DNSSEC records. */
527 if (name
&& (strlen(name
) > SMALLDNAME
-1))
532 big_free
= big_free
->next
;
534 else if ((bignames_left
== 0 && !(flags
& (F_DS
| F_DNSKEY
))) ||
535 !(big_name
= (union bigname
*)whine_malloc(sizeof(union bigname
))))
540 else if (bignames_left
!= 0)
545 /* Got the rest: finally grab entry. */
553 new->name
.bname
= big_name
;
554 new->flags
|= F_BIGNAME
;
558 strcpy(cache_get_name(new), name
);
560 *cache_get_name(new) = 0;
563 new->addr
.addr
= *addr
;
565 new->ttd
= now
+ (time_t)ttl
;
566 new->next
= new_chain
;
572 /* after end of insertion, commit the new entries */
573 void cache_end_insert(void)
580 struct crec
*tmp
= new_chain
->next
;
581 /* drop CNAMEs which didn't find a target. */
582 if (is_outdated_cname_pointer(new_chain
))
583 cache_free(new_chain
);
586 cache_hash(new_chain
);
587 cache_link(new_chain
);
595 struct crec
*cache_find_by_name(struct crec
*crecp
, char *name
, time_t now
, unsigned short prot
)
599 if (crecp
) /* iterating */
603 /* first search, look for relevant entries and push to top of list
604 also free anything which has expired */
605 struct crec
*next
, **up
, **insert
= NULL
, **chainp
= &ans
;
606 unsigned short ins_flags
= 0;
608 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= next
)
610 next
= crecp
->hash_next
;
612 if (!is_expired(now
, crecp
) && !is_outdated_cname_pointer(crecp
))
614 if ((crecp
->flags
& F_FORWARD
) &&
616 ((crecp
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
618 (crecp
->flags
& prot
) &&
619 hostname_isequal(cache_get_name(crecp
), name
))
621 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
624 chainp
= &crecp
->next
;
632 /* Move all but the first entry up the hash chain
633 this implements round-robin.
634 Make sure that re-ordering doesn't break the hash-chain
637 if (insert
&& (crecp
->flags
& (F_REVERSE
| F_IMMORTAL
)) == ins_flags
)
639 *up
= crecp
->hash_next
;
640 crecp
->hash_next
= *insert
;
642 insert
= &crecp
->hash_next
;
649 ins_flags
= crecp
->flags
& (F_REVERSE
| F_IMMORTAL
);
651 up
= &crecp
->hash_next
;
655 /* case : not expired, incorrect entry. */
656 up
= &crecp
->hash_next
;
660 /* expired entry, free it */
661 *up
= crecp
->hash_next
;
662 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
670 *chainp
= cache_head
;
674 (ans
->flags
& F_FORWARD
) &&
676 ((ans
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
678 (ans
->flags
& prot
) &&
679 hostname_isequal(cache_get_name(ans
), name
))
685 struct crec
*cache_find_by_addr(struct crec
*crecp
, struct all_addr
*addr
,
686 time_t now
, unsigned short prot
)
690 int addrlen
= (prot
== F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
692 int addrlen
= INADDRSZ
;
695 if (crecp
) /* iterating */
699 /* first search, look for relevant entries and push to top of list
700 also free anything which has expired. All the reverse entries are at the
701 start of the hash chain, so we can give up when we find the first
704 struct crec
**up
, **chainp
= &ans
;
706 for (i
=0; i
<hash_size
; i
++)
707 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
708 crecp
&& (crecp
->flags
& F_REVERSE
);
709 crecp
= crecp
->hash_next
)
710 if (!is_expired(now
, crecp
))
712 if ((crecp
->flags
& prot
) &&
713 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
715 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
718 chainp
= &crecp
->next
;
726 up
= &crecp
->hash_next
;
730 *up
= crecp
->hash_next
;
731 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
738 *chainp
= cache_head
;
742 (ans
->flags
& F_REVERSE
) &&
743 (ans
->flags
& prot
) &&
744 memcmp(&ans
->addr
.addr
, addr
, addrlen
) == 0)
750 static void add_hosts_cname(struct crec
*target
)
755 for (a
= daemon
->cnames
; a
; a
= a
->next
)
756 if (hostname_isequal(cache_get_name(target
), a
->target
) &&
757 (crec
= whine_malloc(sizeof(struct crec
))))
759 crec
->flags
= F_FORWARD
| F_IMMORTAL
| F_NAMEP
| F_CONFIG
| F_CNAME
;
760 crec
->name
.namep
= a
->alias
;
761 crec
->addr
.cname
.target
.cache
= target
;
762 crec
->addr
.cname
.uid
= target
->uid
;
764 add_hosts_cname(crec
); /* handle chains */
768 static void add_hosts_entry(struct crec
*cache
, struct all_addr
*addr
, int addrlen
,
769 int index
, struct crec
**rhash
, int hashsz
)
771 struct crec
*lookup
= cache_find_by_name(NULL
, cache_get_name(cache
), 0, cache
->flags
& (F_IPV4
| F_IPV6
));
772 int i
, nameexists
= 0;
775 /* Remove duplicates in hosts files. */
776 if (lookup
&& (lookup
->flags
& F_HOSTS
))
779 if (memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
786 /* Ensure there is only one address -> name mapping (first one trumps)
787 We do this by steam here, The entries are kept in hash chains, linked
788 by ->next (which is unused at this point) held in hash buckets in
789 the array rhash, hashed on address. Note that rhash and the values
790 in ->next are only valid whilst reading hosts files: the buckets are
791 then freed, and the ->next pointer used for other things.
793 Only insert each unique address once into this hashing structure.
795 This complexity avoids O(n^2) divergent CPU use whilst reading
796 large (10000 entry) hosts files. */
799 for (j
= 0, i
= 0; i
< addrlen
; i
++)
800 j
= (j
*2 +((unsigned char *)addr
)[i
]) % hashsz
;
802 for (lookup
= rhash
[j
]; lookup
; lookup
= lookup
->next
)
803 if ((lookup
->flags
& cache
->flags
& (F_IPV4
| F_IPV6
)) &&
804 memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
806 cache
->flags
&= ~F_REVERSE
;
810 /* maintain address hash chain, insert new unique address */
813 cache
->next
= rhash
[j
];
818 memcpy(&cache
->addr
.addr
, addr
, addrlen
);
821 /* don't need to do alias stuff for second and subsequent addresses. */
823 add_hosts_cname(cache
);
826 static int eatspace(FILE *f
)
832 if ((c
= getc(f
)) == '#')
833 while (c
!= '\n' && c
!= EOF
)
850 static int gettok(FILE *f
, char *token
)
856 if ((c
= getc(f
)) == EOF
)
857 return (count
== 0) ? EOF
: 1;
859 if (isspace(c
) || c
== '#')
865 if (count
< (MAXDNAME
- 1))
873 static int read_hostsfile(char *filename
, int index
, int cache_size
, struct crec
**rhash
, int hashsz
)
875 FILE *f
= fopen(filename
, "r");
876 char *token
= daemon
->namebuff
, *domain_suffix
= NULL
;
877 int addr_count
= 0, name_count
= cache_size
, lineno
= 0;
878 unsigned short flags
= 0;
879 struct all_addr addr
;
880 int atnl
, addrlen
= 0;
884 my_syslog(LOG_ERR
, _("failed to load names from %s: %s"), filename
, strerror(errno
));
890 while ((atnl
= gettok(f
, token
)) != EOF
)
894 if (inet_pton(AF_INET
, token
, &addr
) > 0)
896 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
;
898 domain_suffix
= get_domain(addr
.addr
.addr4
);
901 else if (inet_pton(AF_INET6
, token
, &addr
) > 0)
903 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
;
905 domain_suffix
= get_domain6(&addr
.addr
.addr6
);
910 my_syslog(LOG_ERR
, _("bad address at %s line %d"), filename
, lineno
);
912 atnl
= gettok(f
, token
);
918 /* rehash every 1000 names. */
919 if ((name_count
- cache_size
) > 1000)
922 cache_size
= name_count
;
931 if ((atnl
= gettok(f
, token
)) == EOF
)
934 fqdn
= !!strchr(token
, '.');
936 if ((canon
= canonicalise(token
, &nomem
)))
938 /* If set, add a version of the name with a default domain appended */
939 if (option_bool(OPT_EXPAND
) && domain_suffix
&& !fqdn
&&
940 (cache
= whine_malloc(sizeof(struct crec
) +
941 strlen(canon
)+2+strlen(domain_suffix
)-SMALLDNAME
)))
943 strcpy(cache
->name
.sname
, canon
);
944 strcat(cache
->name
.sname
, ".");
945 strcat(cache
->name
.sname
, domain_suffix
);
946 cache
->flags
= flags
;
947 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
950 if ((cache
= whine_malloc(sizeof(struct crec
) + strlen(canon
)+1-SMALLDNAME
)))
952 strcpy(cache
->name
.sname
, canon
);
953 cache
->flags
= flags
;
954 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
961 my_syslog(LOG_ERR
, _("bad name at %s line %d"), filename
, lineno
);
968 my_syslog(LOG_INFO
, _("read %s - %d addresses"), filename
, addr_count
);
973 void cache_reload(void)
975 struct crec
*cache
, **up
, *tmp
;
976 int revhashsz
, i
, total_size
= daemon
->cachesize
;
977 struct hostsfile
*ah
;
978 struct host_record
*hr
;
979 struct name_list
*nl
;
981 struct interface_name
*intr
;
986 cache_inserted
= cache_live_freed
= 0;
988 for (i
=0; i
<hash_size
; i
++)
989 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= tmp
)
992 cache_blockdata_free(cache
);
994 tmp
= cache
->hash_next
;
995 if (cache
->flags
& (F_HOSTS
| F_CONFIG
))
997 *up
= cache
->hash_next
;
1000 else if (!(cache
->flags
& F_DHCP
))
1002 *up
= cache
->hash_next
;
1003 if (cache
->flags
& F_BIGNAME
)
1005 cache
->name
.bname
->next
= big_free
;
1006 big_free
= cache
->name
.bname
;
1011 up
= &cache
->hash_next
;
1014 /* Add CNAMEs to interface_names to the cache */
1015 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1016 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
1017 if (hostname_isequal(a
->target
, intr
->name
) &&
1018 ((cache
= whine_malloc(sizeof(struct crec
)))))
1020 cache
->flags
= F_FORWARD
| F_NAMEP
| F_CNAME
| F_IMMORTAL
| F_CONFIG
;
1021 cache
->name
.namep
= a
->alias
;
1022 cache
->addr
.cname
.target
.int_name
= intr
;
1023 cache
->addr
.cname
.uid
= -1;
1025 add_hosts_cname(cache
); /* handle chains */
1029 for (key
= daemon
->dnskeys
; key
; key
= key
->next
)
1030 if ((cache
= whine_malloc(sizeof(struct crec
))) &&
1031 (cache
->addr
.key
.keydata
= blockdata_alloc(key
->key
, key
->keylen
)))
1033 cache
->flags
= F_FORWARD
| F_IMMORTAL
| F_DNSKEY
| F_CONFIG
| F_NAMEP
;
1034 cache
->name
.namep
= key
->name
;
1035 cache
->addr
.key
.keylen
= key
->keylen
;
1036 cache
->addr
.key
.algo
= key
->algo
;
1037 cache
->addr
.key
.flags
= key
->flags
;
1038 cache
->addr
.key
.keytag
= dnskey_keytag(key
->algo
, key
->flags
, (unsigned char *)key
->key
, key
->keylen
);
1039 cache
->uid
= key
->class;
1044 /* borrow the packet buffer for a temporary by-address hash */
1045 memset(daemon
->packet
, 0, daemon
->packet_buff_sz
);
1046 revhashsz
= daemon
->packet_buff_sz
/ sizeof(struct crec
*);
1047 /* we overwrote the buffer... */
1048 daemon
->srv_save
= NULL
;
1050 /* Do host_records in config. */
1051 for (hr
= daemon
->host_records
; hr
; hr
= hr
->next
)
1052 for (nl
= hr
->names
; nl
; nl
= nl
->next
)
1054 if (hr
->addr
.s_addr
!= 0 &&
1055 (cache
= whine_malloc(sizeof(struct crec
))))
1057 cache
->name
.namep
= nl
->name
;
1058 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_NAMEP
| F_CONFIG
;
1059 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr
, INADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1062 if (!IN6_IS_ADDR_UNSPECIFIED(&hr
->addr6
) &&
1063 (cache
= whine_malloc(sizeof(struct crec
))))
1065 cache
->name
.namep
= nl
->name
;
1066 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_NAMEP
| F_CONFIG
;
1067 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr6
, IN6ADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1072 if (option_bool(OPT_NO_HOSTS
) && !daemon
->addn_hosts
)
1074 if (daemon
->cachesize
> 0)
1075 my_syslog(LOG_INFO
, _("cleared cache"));
1079 if (!option_bool(OPT_NO_HOSTS
))
1080 total_size
= read_hostsfile(HOSTSFILE
, 0, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1082 daemon
->addn_hosts
= expand_filelist(daemon
->addn_hosts
);
1083 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1084 if (!(ah
->flags
& AH_INACTIVE
))
1085 total_size
= read_hostsfile(ah
->fname
, ah
->index
, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1089 struct in_addr
a_record_from_hosts(char *name
, time_t now
)
1091 struct crec
*crecp
= NULL
;
1094 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
1095 if (crecp
->flags
& F_HOSTS
)
1096 return *(struct in_addr
*)&crecp
->addr
;
1098 my_syslog(MS_DHCP
| LOG_WARNING
, _("No IPv4 address found for %s"), name
);
1104 void cache_unhash_dhcp(void)
1106 struct crec
*cache
, **up
;
1109 for (i
=0; i
<hash_size
; i
++)
1110 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1111 if (cache
->flags
& F_DHCP
)
1113 *up
= cache
->hash_next
;
1114 cache
->next
= dhcp_spare
;
1118 up
= &cache
->hash_next
;
1121 static void add_dhcp_cname(struct crec
*target
, time_t ttd
)
1123 struct crec
*aliasc
;
1126 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1127 if (hostname_isequal(cache_get_name(target
), a
->target
))
1129 if ((aliasc
= dhcp_spare
))
1130 dhcp_spare
= dhcp_spare
->next
;
1131 else /* need new one */
1132 aliasc
= whine_malloc(sizeof(struct crec
));
1136 aliasc
->flags
= F_FORWARD
| F_NAMEP
| F_DHCP
| F_CNAME
| F_CONFIG
;
1138 aliasc
->flags
|= F_IMMORTAL
;
1141 aliasc
->name
.namep
= a
->alias
;
1142 aliasc
->addr
.cname
.target
.cache
= target
;
1143 aliasc
->addr
.cname
.uid
= target
->uid
;
1145 add_dhcp_cname(aliasc
, ttd
);
1150 void cache_add_dhcp_entry(char *host_name
, int prot
,
1151 struct all_addr
*host_address
, time_t ttd
)
1153 struct crec
*crec
= NULL
, *fail_crec
= NULL
;
1154 unsigned short flags
= F_IPV4
;
1156 size_t addrlen
= sizeof(struct in_addr
);
1159 if (prot
== AF_INET6
)
1162 addrlen
= sizeof(struct in6_addr
);
1166 inet_ntop(prot
, host_address
, daemon
->addrbuff
, ADDRSTRLEN
);
1168 while ((crec
= cache_find_by_name(crec
, host_name
, 0, flags
| F_CNAME
)))
1170 /* check all addresses associated with name */
1171 if (crec
->flags
& (F_HOSTS
| F_CONFIG
))
1173 if (crec
->flags
& F_CNAME
)
1174 my_syslog(MS_DHCP
| LOG_WARNING
,
1175 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1176 host_name
, daemon
->addrbuff
);
1177 else if (memcmp(&crec
->addr
.addr
, host_address
, addrlen
) == 0)
1182 else if (!(crec
->flags
& F_DHCP
))
1184 cache_scan_free(host_name
, NULL
, 0, crec
->flags
& (flags
| F_CNAME
| F_FORWARD
));
1185 /* scan_free deletes all addresses associated with name */
1190 /* if in hosts, don't need DHCP record */
1194 /* Name in hosts, address doesn't match */
1197 inet_ntop(prot
, &fail_crec
->addr
.addr
, daemon
->namebuff
, MAXDNAME
);
1198 my_syslog(MS_DHCP
| LOG_WARNING
,
1199 _("not giving name %s to the DHCP lease of %s because "
1200 "the name exists in %s with address %s"),
1201 host_name
, daemon
->addrbuff
,
1202 record_source(fail_crec
->uid
), daemon
->namebuff
);
1206 if ((crec
= cache_find_by_addr(NULL
, (struct all_addr
*)host_address
, 0, flags
)))
1208 if (crec
->flags
& F_NEG
)
1211 cache_scan_free(NULL
, (struct all_addr
*)host_address
, 0, flags
);
1217 if ((crec
= dhcp_spare
))
1218 dhcp_spare
= dhcp_spare
->next
;
1219 else /* need new one */
1220 crec
= whine_malloc(sizeof(struct crec
));
1222 if (crec
) /* malloc may fail */
1224 crec
->flags
= flags
| F_NAMEP
| F_DHCP
| F_FORWARD
;
1226 crec
->flags
|= F_IMMORTAL
;
1229 crec
->addr
.addr
= *host_address
;
1230 crec
->name
.namep
= host_name
;
1234 add_dhcp_cname(crec
, ttd
);
1240 void dump_cache(time_t now
)
1242 struct server
*serv
, *serv1
;
1245 my_syslog(LOG_INFO
, _("time %lu"), (unsigned long)now
);
1246 my_syslog(LOG_INFO
, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1247 daemon
->cachesize
, cache_live_freed
, cache_inserted
);
1248 my_syslog(LOG_INFO
, _("queries forwarded %u, queries answered locally %u"),
1249 daemon
->queries_forwarded
, daemon
->local_answer
);
1251 my_syslog(LOG_INFO
, _("queries for authoritative zones %u"), daemon
->auth_answer
);
1257 /* sum counts from different records for same server */
1258 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1259 serv
->flags
&= ~SERV_COUNTED
;
1261 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1263 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)))
1266 unsigned int queries
= 0, failed_queries
= 0;
1267 for (serv1
= serv
; serv1
; serv1
= serv1
->next
)
1268 if (!(serv1
->flags
&
1269 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)) &&
1270 sockaddr_isequal(&serv
->addr
, &serv1
->addr
))
1272 serv1
->flags
|= SERV_COUNTED
;
1273 queries
+= serv1
->queries
;
1274 failed_queries
+= serv1
->failed_queries
;
1276 port
= prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
1277 my_syslog(LOG_INFO
, _("server %s#%d: queries sent %u, retried or failed %u"), daemon
->addrbuff
, port
, queries
, failed_queries
);
1280 if (option_bool(OPT_DEBUG
) || option_bool(OPT_LOG
))
1282 struct crec
*cache
;
1284 my_syslog(LOG_INFO
, "Host Address Flags Expires");
1286 for (i
=0; i
<hash_size
; i
++)
1287 for (cache
= hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1289 char *a
= daemon
->addrbuff
, *p
= daemon
->namebuff
, *n
= cache_get_name(cache
);
1291 if (strlen(n
) == 0 && !(cache
->flags
& F_REVERSE
))
1293 p
+= sprintf(p
, "%-40.40s ", n
);
1294 if ((cache
->flags
& F_CNAME
) && !is_outdated_cname_pointer(cache
))
1295 a
= cache_get_cname_target(cache
);
1297 else if (cache
->flags
& F_DS
)
1299 if (cache
->flags
& F_DNSKEY
)
1303 querystr("", tp
, cache
->addr
.sig
.type_covered
);
1304 a
= daemon
->addrbuff
;
1305 sprintf(a
, "%5u %3u %s", cache
->addr
.sig
.keytag
,
1306 cache
->addr
.sig
.algo
, tp
);
1310 a
= daemon
->addrbuff
;
1311 sprintf(a
, "%5u %3u %3u", cache
->addr
.ds
.keytag
,
1312 cache
->addr
.ds
.algo
, cache
->addr
.ds
.digest
);
1315 else if (cache
->flags
& F_DNSKEY
)
1317 a
= daemon
->addrbuff
;
1318 sprintf(a
, "%5u %3u %3u", cache
->addr
.key
.keytag
,
1319 cache
->addr
.key
.algo
, cache
->addr
.key
.flags
);
1322 else if (!(cache
->flags
& F_NEG
) || !(cache
->flags
& F_FORWARD
))
1324 a
= daemon
->addrbuff
;
1325 if (cache
->flags
& F_IPV4
)
1326 inet_ntop(AF_INET
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1328 else if (cache
->flags
& F_IPV6
)
1329 inet_ntop(AF_INET6
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1333 if (cache
->flags
& F_IPV4
)
1335 else if (cache
->flags
& F_IPV6
)
1337 else if (cache
->flags
& F_CNAME
)
1340 else if ((cache
->flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
))
1341 t
= "G"; /* DNSKEY and DS set -> RRISG */
1342 else if (cache
->flags
& F_DS
)
1344 else if (cache
->flags
& F_DNSKEY
)
1347 p
+= sprintf(p
, "%-30.30s %s%s%s%s%s%s%s%s%s ", a
, t
,
1348 cache
->flags
& F_FORWARD
? "F" : " ",
1349 cache
->flags
& F_REVERSE
? "R" : " ",
1350 cache
->flags
& F_IMMORTAL
? "I" : " ",
1351 cache
->flags
& F_DHCP
? "D" : " ",
1352 cache
->flags
& F_NEG
? "N" : " ",
1353 cache
->flags
& F_NXDOMAIN
? "X" : " ",
1354 cache
->flags
& F_HOSTS
? "H" : " ",
1355 cache
->flags
& F_DNSSECOK
? "V" : " ");
1356 #ifdef HAVE_BROKEN_RTC
1357 p
+= sprintf(p
, "%lu", cache
->flags
& F_IMMORTAL
? 0: (unsigned long)(cache
->ttd
- now
));
1359 p
+= sprintf(p
, "%s", cache
->flags
& F_IMMORTAL
? "\n" : ctime(&(cache
->ttd
)));
1360 /* ctime includes trailing \n - eat it */
1363 my_syslog(LOG_INFO
, daemon
->namebuff
);
1368 char *record_source(int index
)
1370 struct hostsfile
*ah
;
1375 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1376 if (ah
->index
== index
)
1382 void querystr(char *desc
, char *str
, unsigned short type
)
1386 sprintf(str
, "%s[type=%d]", desc
, type
);
1387 for (i
= 0; i
< (sizeof(typestr
)/sizeof(typestr
[0])); i
++)
1388 if (typestr
[i
].type
== type
)
1389 sprintf(str
,"%s[%s]", desc
, typestr
[i
].name
);
1392 void log_query(unsigned int flags
, char *name
, struct all_addr
*addr
, char *arg
)
1394 char *source
, *dest
= daemon
->addrbuff
;
1397 if (!option_bool(OPT_LOG
))
1402 if (flags
& F_KEYTAG
)
1403 sprintf(daemon
->addrbuff
, arg
, addr
->addr
.keytag
);
1407 inet_ntop(flags
& F_IPV4
? AF_INET
: AF_INET6
,
1408 addr
, daemon
->addrbuff
, ADDRSTRLEN
);
1410 strncpy(daemon
->addrbuff
, inet_ntoa(addr
->addr
.addr4
), ADDRSTRLEN
);
1417 if (flags
& F_REVERSE
)
1420 name
= daemon
->addrbuff
;
1425 if (flags
& F_NXDOMAIN
)
1428 dest
= "NXDOMAIN-IPv4";
1429 else if (flags
& F_IPV6
)
1430 dest
= "NXDOMAIN-IPv6";
1437 dest
= "NODATA-IPv4";
1438 else if (flags
& F_IPV6
)
1439 dest
= "NODATA-IPv6";
1444 else if (flags
& F_CNAME
)
1446 else if (flags
& F_RRNAME
)
1449 if (flags
& F_CONFIG
)
1451 else if (flags
& F_DHCP
)
1453 else if (flags
& F_HOSTS
)
1455 else if (flags
& F_UPSTREAM
)
1457 else if (flags
& F_SECSTAT
)
1458 source
= "validation";
1459 else if (flags
& F_AUTH
)
1461 else if (flags
& F_SERVER
)
1463 source
= "forwarded";
1466 else if (flags
& F_QUERY
)
1471 else if (flags
& F_DNSSEC
)
1479 if (strlen(name
) == 0)
1482 my_syslog(LOG_INFO
, "%s %s %s %s", source
, name
, verb
, dest
);