]>
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
))
334 if ((flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) || ((crecp
->flags
| flags
) & F_CNAME
))
336 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
338 *up
= crecp
->hash_next
;
345 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
346 type-covered sensitive for RRSIG */
347 if (flags
& crecp
->flags
& (F_DNSKEY
| F_DS
))
350 switch (flags
& (F_DS
| F_DNSKEY
))
353 if (crecp
->addr
.ds
.class == addr
->addr
.dnssec
.class)
358 if (crecp
->addr
.key
.class == addr
->addr
.dnssec
.class)
362 /* Both set -> RRSIG */
363 case F_DS
| F_DNSKEY
:
364 if (crecp
->addr
.sig
.class == addr
->addr
.dnssec
.class &&
365 crecp
->addr
.sig
.type_covered
== addr
->addr
.dnssec
.type
)
372 if (crecp
->flags
& F_CONFIG
)
374 *up
= crecp
->hash_next
;
382 up
= &crecp
->hash_next
;
389 int addrlen
= (flags
& F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
391 int addrlen
= INADDRSZ
;
393 for (i
= 0; i
< hash_size
; i
++)
394 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
395 crecp
&& ((crecp
->flags
& F_REVERSE
) || !(crecp
->flags
& F_IMMORTAL
));
396 crecp
= crecp
->hash_next
)
397 if (is_expired(now
, crecp
))
399 *up
= crecp
->hash_next
;
400 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
406 else if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)) &&
407 (flags
& crecp
->flags
& F_REVERSE
) &&
408 (flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
409 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
411 *up
= crecp
->hash_next
;
416 up
= &crecp
->hash_next
;
422 /* Note: The normal calling sequence is
427 but an abort can cause the cache_end_insert to be missed
428 in which can the next cache_start_insert cleans things up. */
430 void cache_start_insert(void)
432 /* Free any entries which didn't get committed during the last
437 struct crec
*tmp
= new_chain
->next
;
438 cache_free(new_chain
);
445 struct crec
*cache_insert(char *name
, struct all_addr
*addr
,
446 time_t now
, unsigned long ttl
, unsigned short flags
)
449 union bigname
*big_name
= NULL
;
450 int freed_all
= flags
& F_REVERSE
;
453 if (daemon
->max_cache_ttl
!= 0 && daemon
->max_cache_ttl
< ttl
)
454 ttl
= daemon
->max_cache_ttl
;
456 /* Don't log keys here, done elsewhere */
457 if (flags
& (F_IPV4
| F_IPV6
| F_CNAME
))
458 log_query(flags
| F_UPSTREAM
, name
, addr
, NULL
);
460 /* if previous insertion failed give up now. */
464 /* First remove any expired entries and entries for the name/address we
465 are currently inserting. Fail is we attempt to delete a name from
466 /etc/hosts or DHCP. */
467 if (!cache_scan_free(name
, addr
, now
, flags
))
473 /* Now get a cache entry from the end of the LRU list */
475 if (!(new = cache_tail
)) /* no entries left - cache is too small, bail */
481 /* End of LRU list is still in use: if we didn't scan all the hash
482 chains for expired entries do that now. If we already tried that
483 then it's time to start spilling things. */
485 if (new->flags
& (F_FORWARD
| F_REVERSE
))
487 /* If free_avail set, we believe that an entry has been freed.
488 Bugs have been known to make this not true, resulting in
489 a tight loop here. If that happens, abandon the
490 insert. Once in this state, all inserts will probably fail. */
499 free_avail
= 1; /* Must be free space now. */
500 cache_scan_free(cache_get_name(new), &new->addr
.addr
, now
, new->flags
);
505 cache_scan_free(NULL
, NULL
, now
, 0);
511 /* Check if we need to and can allocate extra memory for a long name.
512 If that fails, give up now. */
513 if (name
&& (strlen(name
) > SMALLDNAME
-1))
518 big_free
= big_free
->next
;
520 else if (!bignames_left
||
521 !(big_name
= (union bigname
*)whine_malloc(sizeof(union bigname
))))
531 /* Got the rest: finally grab entry. */
539 new->name
.bname
= big_name
;
540 new->flags
|= F_BIGNAME
;
544 strcpy(cache_get_name(new), name
);
546 *cache_get_name(new) = 0;
549 new->addr
.addr
= *addr
;
551 new->ttd
= now
+ (time_t)ttl
;
552 new->next
= new_chain
;
558 /* after end of insertion, commit the new entries */
559 void cache_end_insert(void)
566 struct crec
*tmp
= new_chain
->next
;
567 /* drop CNAMEs which didn't find a target. */
568 if (is_outdated_cname_pointer(new_chain
))
569 cache_free(new_chain
);
572 cache_hash(new_chain
);
573 cache_link(new_chain
);
581 struct crec
*cache_find_by_name(struct crec
*crecp
, char *name
, time_t now
, unsigned short prot
)
585 if (crecp
) /* iterating */
589 /* first search, look for relevant entries and push to top of list
590 also free anything which has expired */
591 struct crec
*next
, **up
, **insert
= NULL
, **chainp
= &ans
;
592 unsigned short ins_flags
= 0;
594 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= next
)
596 next
= crecp
->hash_next
;
598 if (!is_expired(now
, crecp
) && !is_outdated_cname_pointer(crecp
))
600 if ((crecp
->flags
& F_FORWARD
) &&
602 ((crecp
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
604 (crecp
->flags
& prot
) &&
605 hostname_isequal(cache_get_name(crecp
), name
))
607 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
610 chainp
= &crecp
->next
;
618 /* Move all but the first entry up the hash chain
619 this implements round-robin.
620 Make sure that re-ordering doesn't break the hash-chain
623 if (insert
&& (crecp
->flags
& (F_REVERSE
| F_IMMORTAL
)) == ins_flags
)
625 *up
= crecp
->hash_next
;
626 crecp
->hash_next
= *insert
;
628 insert
= &crecp
->hash_next
;
635 ins_flags
= crecp
->flags
& (F_REVERSE
| F_IMMORTAL
);
637 up
= &crecp
->hash_next
;
641 /* case : not expired, incorrect entry. */
642 up
= &crecp
->hash_next
;
646 /* expired entry, free it */
647 *up
= crecp
->hash_next
;
648 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
656 *chainp
= cache_head
;
660 (ans
->flags
& F_FORWARD
) &&
662 ((ans
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
664 (ans
->flags
& prot
) &&
665 hostname_isequal(cache_get_name(ans
), name
))
671 struct crec
*cache_find_by_addr(struct crec
*crecp
, struct all_addr
*addr
,
672 time_t now
, unsigned short prot
)
676 int addrlen
= (prot
== F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
678 int addrlen
= INADDRSZ
;
681 if (crecp
) /* iterating */
685 /* first search, look for relevant entries and push to top of list
686 also free anything which has expired. All the reverse entries are at the
687 start of the hash chain, so we can give up when we find the first
690 struct crec
**up
, **chainp
= &ans
;
692 for (i
=0; i
<hash_size
; i
++)
693 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
694 crecp
&& (crecp
->flags
& F_REVERSE
);
695 crecp
= crecp
->hash_next
)
696 if (!is_expired(now
, crecp
))
698 if ((crecp
->flags
& prot
) &&
699 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
701 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
704 chainp
= &crecp
->next
;
712 up
= &crecp
->hash_next
;
716 *up
= crecp
->hash_next
;
717 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
724 *chainp
= cache_head
;
728 (ans
->flags
& F_REVERSE
) &&
729 (ans
->flags
& prot
) &&
730 memcmp(&ans
->addr
.addr
, addr
, addrlen
) == 0)
736 static void add_hosts_cname(struct crec
*target
)
741 for (a
= daemon
->cnames
; a
; a
= a
->next
)
742 if (hostname_isequal(cache_get_name(target
), a
->target
) &&
743 (crec
= whine_malloc(sizeof(struct crec
))))
745 crec
->flags
= F_FORWARD
| F_IMMORTAL
| F_NAMEP
| F_CONFIG
| F_CNAME
| F_DNSSECOK
;
746 crec
->name
.namep
= a
->alias
;
747 crec
->addr
.cname
.target
.cache
= target
;
748 crec
->addr
.cname
.uid
= target
->uid
;
750 add_hosts_cname(crec
); /* handle chains */
754 static void add_hosts_entry(struct crec
*cache
, struct all_addr
*addr
, int addrlen
,
755 int index
, struct crec
**rhash
, int hashsz
)
757 struct crec
*lookup
= cache_find_by_name(NULL
, cache_get_name(cache
), 0, cache
->flags
& (F_IPV4
| F_IPV6
));
758 int i
, nameexists
= 0;
761 /* Remove duplicates in hosts files. */
762 if (lookup
&& (lookup
->flags
& F_HOSTS
))
765 if (memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
772 /* Ensure there is only one address -> name mapping (first one trumps)
773 We do this by steam here, The entries are kept in hash chains, linked
774 by ->next (which is unused at this point) held in hash buckets in
775 the array rhash, hashed on address. Note that rhash and the values
776 in ->next are only valid whilst reading hosts files: the buckets are
777 then freed, and the ->next pointer used for other things.
779 Only insert each unique address once into this hashing structure.
781 This complexity avoids O(n^2) divergent CPU use whilst reading
782 large (10000 entry) hosts files. */
785 for (j
= 0, i
= 0; i
< addrlen
; i
++)
786 j
= (j
*2 +((unsigned char *)addr
)[i
]) % hashsz
;
788 for (lookup
= rhash
[j
]; lookup
; lookup
= lookup
->next
)
789 if ((lookup
->flags
& cache
->flags
& (F_IPV4
| F_IPV6
)) &&
790 memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
792 cache
->flags
&= ~F_REVERSE
;
796 /* maintain address hash chain, insert new unique address */
799 cache
->next
= rhash
[j
];
804 memcpy(&cache
->addr
.addr
, addr
, addrlen
);
807 /* don't need to do alias stuff for second and subsequent addresses. */
809 add_hosts_cname(cache
);
812 static int eatspace(FILE *f
)
818 if ((c
= getc(f
)) == '#')
819 while (c
!= '\n' && c
!= EOF
)
836 static int gettok(FILE *f
, char *token
)
842 if ((c
= getc(f
)) == EOF
)
843 return (count
== 0) ? EOF
: 1;
845 if (isspace(c
) || c
== '#')
851 if (count
< (MAXDNAME
- 1))
859 static int read_hostsfile(char *filename
, int index
, int cache_size
, struct crec
**rhash
, int hashsz
)
861 FILE *f
= fopen(filename
, "r");
862 char *token
= daemon
->namebuff
, *domain_suffix
= NULL
;
863 int addr_count
= 0, name_count
= cache_size
, lineno
= 0;
864 unsigned short flags
= 0;
865 struct all_addr addr
;
866 int atnl
, addrlen
= 0;
870 my_syslog(LOG_ERR
, _("failed to load names from %s: %s"), filename
, strerror(errno
));
876 while ((atnl
= gettok(f
, token
)) != EOF
)
880 if (inet_pton(AF_INET
, token
, &addr
) > 0)
882 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_DNSSECOK
;
884 domain_suffix
= get_domain(addr
.addr
.addr4
);
887 else if (inet_pton(AF_INET6
, token
, &addr
) > 0)
889 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_DNSSECOK
;
891 domain_suffix
= get_domain6(&addr
.addr
.addr6
);
896 my_syslog(LOG_ERR
, _("bad address at %s line %d"), filename
, lineno
);
898 atnl
= gettok(f
, token
);
904 /* rehash every 1000 names. */
905 if ((name_count
- cache_size
) > 1000)
908 cache_size
= name_count
;
917 if ((atnl
= gettok(f
, token
)) == EOF
)
920 fqdn
= !!strchr(token
, '.');
922 if ((canon
= canonicalise(token
, &nomem
)))
924 /* If set, add a version of the name with a default domain appended */
925 if (option_bool(OPT_EXPAND
) && domain_suffix
&& !fqdn
&&
926 (cache
= whine_malloc(sizeof(struct crec
) +
927 strlen(canon
)+2+strlen(domain_suffix
)-SMALLDNAME
)))
929 strcpy(cache
->name
.sname
, canon
);
930 strcat(cache
->name
.sname
, ".");
931 strcat(cache
->name
.sname
, domain_suffix
);
932 cache
->flags
= flags
;
933 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
936 if ((cache
= whine_malloc(sizeof(struct crec
) + strlen(canon
)+1-SMALLDNAME
)))
938 strcpy(cache
->name
.sname
, canon
);
939 cache
->flags
= flags
;
940 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
947 my_syslog(LOG_ERR
, _("bad name at %s line %d"), filename
, lineno
);
954 my_syslog(LOG_INFO
, _("read %s - %d addresses"), filename
, addr_count
);
959 void cache_reload(void)
961 struct crec
*cache
, **up
, *tmp
;
962 int revhashsz
, i
, total_size
= daemon
->cachesize
;
963 struct hostsfile
*ah
;
964 struct host_record
*hr
;
965 struct name_list
*nl
;
967 struct interface_name
*intr
;
972 cache_inserted
= cache_live_freed
= 0;
974 for (i
=0; i
<hash_size
; i
++)
975 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= tmp
)
978 if (cache
->flags
& (F_DNSKEY
| F_DS
))
979 blockdata_free(cache
->addr
.key
.keydata
);
981 tmp
= cache
->hash_next
;
982 if (cache
->flags
& (F_HOSTS
| F_CONFIG
))
984 *up
= cache
->hash_next
;
987 else if (!(cache
->flags
& F_DHCP
))
989 *up
= cache
->hash_next
;
990 if (cache
->flags
& F_BIGNAME
)
992 cache
->name
.bname
->next
= big_free
;
993 big_free
= cache
->name
.bname
;
998 up
= &cache
->hash_next
;
1001 /* Add CNAMEs to interface_names to the cache */
1002 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1003 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
1004 if (hostname_isequal(a
->target
, intr
->name
) &&
1005 ((cache
= whine_malloc(sizeof(struct crec
)))))
1007 cache
->flags
= F_FORWARD
| F_NAMEP
| F_CNAME
| F_IMMORTAL
| F_CONFIG
| F_DNSSECOK
;
1008 cache
->name
.namep
= a
->alias
;
1009 cache
->addr
.cname
.target
.int_name
= intr
;
1010 cache
->addr
.cname
.uid
= -1;
1012 add_hosts_cname(cache
); /* handle chains */
1016 for (key
= daemon
->dnskeys
; key
; key
= key
->next
)
1017 if ((cache
= whine_malloc(sizeof(struct crec
))) &&
1018 (cache
->addr
.key
.keydata
= blockdata_alloc(key
->key
, key
->keylen
)))
1020 cache
->flags
= F_FORWARD
| F_IMMORTAL
| F_DNSKEY
| F_CONFIG
| F_NAMEP
;
1021 cache
->name
.namep
= key
->name
;
1022 cache
->uid
= key
->keylen
;
1023 cache
->addr
.key
.algo
= key
->algo
;
1024 cache
->addr
.key
.flags
= key
->flags
;
1025 cache
->addr
.key
.keytag
= dnskey_keytag(key
->algo
, key
->flags
, (unsigned char *)key
->key
, key
->keylen
);
1026 cache
->addr
.key
.class = C_IN
; /* TODO - in option? */
1031 /* borrow the packet buffer for a temporary by-address hash */
1032 memset(daemon
->packet
, 0, daemon
->packet_buff_sz
);
1033 revhashsz
= daemon
->packet_buff_sz
/ sizeof(struct crec
*);
1034 /* we overwrote the buffer... */
1035 daemon
->srv_save
= NULL
;
1037 /* Do host_records in config. */
1038 for (hr
= daemon
->host_records
; hr
; hr
= hr
->next
)
1039 for (nl
= hr
->names
; nl
; nl
= nl
->next
)
1041 if (hr
->addr
.s_addr
!= 0 &&
1042 (cache
= whine_malloc(sizeof(struct crec
))))
1044 cache
->name
.namep
= nl
->name
;
1045 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_NAMEP
| F_CONFIG
| F_DNSSECOK
;
1046 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr
, INADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1049 if (!IN6_IS_ADDR_UNSPECIFIED(&hr
->addr6
) &&
1050 (cache
= whine_malloc(sizeof(struct crec
))))
1052 cache
->name
.namep
= nl
->name
;
1053 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_NAMEP
| F_CONFIG
| F_DNSSECOK
;
1054 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr6
, IN6ADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1059 if (option_bool(OPT_NO_HOSTS
) && !daemon
->addn_hosts
)
1061 if (daemon
->cachesize
> 0)
1062 my_syslog(LOG_INFO
, _("cleared cache"));
1066 if (!option_bool(OPT_NO_HOSTS
))
1067 total_size
= read_hostsfile(HOSTSFILE
, 0, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1069 daemon
->addn_hosts
= expand_filelist(daemon
->addn_hosts
);
1070 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1071 if (!(ah
->flags
& AH_INACTIVE
))
1072 total_size
= read_hostsfile(ah
->fname
, ah
->index
, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1076 struct in_addr
a_record_from_hosts(char *name
, time_t now
)
1078 struct crec
*crecp
= NULL
;
1081 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
1082 if (crecp
->flags
& F_HOSTS
)
1083 return *(struct in_addr
*)&crecp
->addr
;
1085 my_syslog(MS_DHCP
| LOG_WARNING
, _("No IPv4 address found for %s"), name
);
1091 void cache_unhash_dhcp(void)
1093 struct crec
*cache
, **up
;
1096 for (i
=0; i
<hash_size
; i
++)
1097 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1098 if (cache
->flags
& F_DHCP
)
1100 *up
= cache
->hash_next
;
1101 cache
->next
= dhcp_spare
;
1105 up
= &cache
->hash_next
;
1108 static void add_dhcp_cname(struct crec
*target
, time_t ttd
)
1110 struct crec
*aliasc
;
1113 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1114 if (hostname_isequal(cache_get_name(target
), a
->target
))
1116 if ((aliasc
= dhcp_spare
))
1117 dhcp_spare
= dhcp_spare
->next
;
1118 else /* need new one */
1119 aliasc
= whine_malloc(sizeof(struct crec
));
1123 aliasc
->flags
= F_FORWARD
| F_NAMEP
| F_DHCP
| F_CNAME
| F_CONFIG
| F_DNSSECOK
;
1125 aliasc
->flags
|= F_IMMORTAL
;
1128 aliasc
->name
.namep
= a
->alias
;
1129 aliasc
->addr
.cname
.target
.cache
= target
;
1130 aliasc
->addr
.cname
.uid
= target
->uid
;
1132 add_dhcp_cname(aliasc
, ttd
);
1137 void cache_add_dhcp_entry(char *host_name
, int prot
,
1138 struct all_addr
*host_address
, time_t ttd
)
1140 struct crec
*crec
= NULL
, *fail_crec
= NULL
;
1141 unsigned short flags
= F_IPV4
;
1143 size_t addrlen
= sizeof(struct in_addr
);
1146 if (prot
== AF_INET6
)
1149 addrlen
= sizeof(struct in6_addr
);
1153 inet_ntop(prot
, host_address
, daemon
->addrbuff
, ADDRSTRLEN
);
1155 while ((crec
= cache_find_by_name(crec
, host_name
, 0, flags
| F_CNAME
)))
1157 /* check all addresses associated with name */
1158 if (crec
->flags
& (F_HOSTS
| F_CONFIG
))
1160 if (crec
->flags
& F_CNAME
)
1161 my_syslog(MS_DHCP
| LOG_WARNING
,
1162 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1163 host_name
, daemon
->addrbuff
);
1164 else if (memcmp(&crec
->addr
.addr
, host_address
, addrlen
) == 0)
1169 else if (!(crec
->flags
& F_DHCP
))
1171 cache_scan_free(host_name
, NULL
, 0, crec
->flags
& (flags
| F_CNAME
| F_FORWARD
));
1172 /* scan_free deletes all addresses associated with name */
1177 /* if in hosts, don't need DHCP record */
1181 /* Name in hosts, address doesn't match */
1184 inet_ntop(prot
, &fail_crec
->addr
.addr
, daemon
->namebuff
, MAXDNAME
);
1185 my_syslog(MS_DHCP
| LOG_WARNING
,
1186 _("not giving name %s to the DHCP lease of %s because "
1187 "the name exists in %s with address %s"),
1188 host_name
, daemon
->addrbuff
,
1189 record_source(fail_crec
->uid
), daemon
->namebuff
);
1193 if ((crec
= cache_find_by_addr(NULL
, (struct all_addr
*)host_address
, 0, flags
)))
1195 if (crec
->flags
& F_NEG
)
1198 cache_scan_free(NULL
, (struct all_addr
*)host_address
, 0, flags
);
1204 if ((crec
= dhcp_spare
))
1205 dhcp_spare
= dhcp_spare
->next
;
1206 else /* need new one */
1207 crec
= whine_malloc(sizeof(struct crec
));
1209 if (crec
) /* malloc may fail */
1211 crec
->flags
= flags
| F_NAMEP
| F_DHCP
| F_FORWARD
| F_DNSSECOK
;
1213 crec
->flags
|= F_IMMORTAL
;
1216 crec
->addr
.addr
= *host_address
;
1217 crec
->name
.namep
= host_name
;
1221 add_dhcp_cname(crec
, ttd
);
1227 void dump_cache(time_t now
)
1229 struct server
*serv
, *serv1
;
1231 my_syslog(LOG_INFO
, _("time %lu"), (unsigned long)now
);
1232 my_syslog(LOG_INFO
, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1233 daemon
->cachesize
, cache_live_freed
, cache_inserted
);
1234 my_syslog(LOG_INFO
, _("queries forwarded %u, queries answered locally %u"),
1235 daemon
->queries_forwarded
, daemon
->local_answer
);
1237 my_syslog(LOG_INFO
, _("queries for authoritative zones %u"), daemon
->auth_answer
);
1243 /* sum counts from different records for same server */
1244 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1245 serv
->flags
&= ~SERV_COUNTED
;
1247 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1249 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)))
1252 unsigned int queries
= 0, failed_queries
= 0;
1253 for (serv1
= serv
; serv1
; serv1
= serv1
->next
)
1254 if (!(serv1
->flags
&
1255 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)) &&
1256 sockaddr_isequal(&serv
->addr
, &serv1
->addr
))
1258 serv1
->flags
|= SERV_COUNTED
;
1259 queries
+= serv1
->queries
;
1260 failed_queries
+= serv1
->failed_queries
;
1262 port
= prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
1263 my_syslog(LOG_INFO
, _("server %s#%d: queries sent %u, retried or failed %u"), daemon
->addrbuff
, port
, queries
, failed_queries
);
1266 if (option_bool(OPT_DEBUG
) || option_bool(OPT_LOG
))
1268 struct crec
*cache
;
1270 my_syslog(LOG_INFO
, "Host Address Flags Expires");
1272 for (i
=0; i
<hash_size
; i
++)
1273 for (cache
= hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1275 char *a
= daemon
->addrbuff
, *p
= daemon
->namebuff
, *n
= cache_get_name(cache
);
1279 p
+= sprintf(p
, "%-40.40s ", n
);
1280 if ((cache
->flags
& F_CNAME
) && !is_outdated_cname_pointer(cache
))
1281 a
= cache_get_cname_target(cache
);
1283 else if (cache
->flags
& F_DS
)
1285 a
= daemon
->addrbuff
;
1286 sprintf(a
, "%5u %3u %3u", cache
->addr
.ds
.keytag
,
1287 cache
->addr
.ds
.algo
, cache
->addr
.ds
.digest
);
1289 else if (cache
->flags
& F_DNSKEY
)
1291 a
= daemon
->addrbuff
;
1292 sprintf(a
, "%5u %3u %3u", cache
->addr
.key
.keytag
,
1293 cache
->addr
.key
.algo
, cache
->addr
.key
.flags
);
1296 else if (!(cache
->flags
& F_NEG
) || !(cache
->flags
& F_FORWARD
))
1298 a
= daemon
->addrbuff
;
1299 if (cache
->flags
& F_IPV4
)
1300 inet_ntop(AF_INET
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1302 else if (cache
->flags
& F_IPV6
)
1303 inet_ntop(AF_INET6
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1307 p
+= sprintf(p
, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a
,
1308 cache
->flags
& F_IPV4
? "4" : "",
1309 cache
->flags
& F_IPV6
? "6" : "",
1310 cache
->flags
& F_DNSKEY
? "K" : "",
1311 cache
->flags
& F_DS
? "S" : "",
1312 cache
->flags
& F_CNAME
? "C" : "",
1313 cache
->flags
& F_FORWARD
? "F" : " ",
1314 cache
->flags
& F_REVERSE
? "R" : " ",
1315 cache
->flags
& F_IMMORTAL
? "I" : " ",
1316 cache
->flags
& F_DHCP
? "D" : " ",
1317 cache
->flags
& F_NEG
? "N" : " ",
1318 cache
->flags
& F_NXDOMAIN
? "X" : " ",
1319 cache
->flags
& F_HOSTS
? "H" : " ",
1320 cache
->flags
& F_DNSSECOK
? "V" : " ");
1321 #ifdef HAVE_BROKEN_RTC
1322 p
+= sprintf(p
, "%lu", cache
->flags
& F_IMMORTAL
? 0: (unsigned long)(cache
->ttd
- now
));
1324 p
+= sprintf(p
, "%s", cache
->flags
& F_IMMORTAL
? "\n" : ctime(&(cache
->ttd
)));
1325 /* ctime includes trailing \n - eat it */
1328 my_syslog(LOG_INFO
, daemon
->namebuff
);
1333 char *record_source(int index
)
1335 struct hostsfile
*ah
;
1340 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1341 if (ah
->index
== index
)
1347 void querystr(char *desc
, char *str
, unsigned short type
)
1351 sprintf(str
, "%s[type=%d]", desc
, type
);
1352 for (i
= 0; i
< (sizeof(typestr
)/sizeof(typestr
[0])); i
++)
1353 if (typestr
[i
].type
== type
)
1354 sprintf(str
,"%s[%s]", desc
, typestr
[i
].name
);
1357 void log_query(unsigned int flags
, char *name
, struct all_addr
*addr
, char *arg
)
1359 char *source
, *dest
= daemon
->addrbuff
;
1362 if (!option_bool(OPT_LOG
))
1367 if (flags
& F_KEYTAG
)
1368 sprintf(daemon
->addrbuff
, arg
, addr
->addr
.keytag
);
1372 inet_ntop(flags
& F_IPV4
? AF_INET
: AF_INET6
,
1373 addr
, daemon
->addrbuff
, ADDRSTRLEN
);
1375 strncpy(daemon
->addrbuff
, inet_ntoa(addr
->addr
.addr4
), ADDRSTRLEN
);
1382 if (flags
& F_REVERSE
)
1385 name
= daemon
->addrbuff
;
1390 if (flags
& F_NXDOMAIN
)
1393 dest
= "NXDOMAIN-IPv4";
1394 else if (flags
& F_IPV6
)
1395 dest
= "NXDOMAIN-IPv6";
1402 dest
= "NODATA-IPv4";
1403 else if (flags
& F_IPV6
)
1404 dest
= "NODATA-IPv6";
1409 else if (flags
& F_CNAME
)
1411 else if (flags
& F_RRNAME
)
1414 if (flags
& F_CONFIG
)
1416 else if (flags
& F_DHCP
)
1418 else if (flags
& F_HOSTS
)
1420 else if (flags
& F_UPSTREAM
)
1422 else if (flags
& F_SECSTAT
)
1423 source
= "validation";
1424 else if (flags
& F_AUTH
)
1426 else if (flags
& F_SERVER
)
1428 source
= "forwarded";
1431 else if (flags
& F_QUERY
)
1436 else if (flags
& F_DNSSEC
)
1444 if (strlen(name
) == 0)
1447 my_syslog(LOG_INFO
, "%s %s %s %s", source
, name
, verb
, dest
);