]>
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
)) == (crecp
->flags
& (F_DNSKEY
| F_DS
)) &&
349 crecp
->uid
== addr
->addr
.dnssec
.class &&
350 (!((flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
)) ||
351 crecp
->addr
.sig
.type_covered
== addr
->addr
.dnssec
.type
))
353 if (crecp
->flags
& F_CONFIG
)
355 *up
= crecp
->hash_next
;
362 up
= &crecp
->hash_next
;
369 int addrlen
= (flags
& F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
371 int addrlen
= INADDRSZ
;
373 for (i
= 0; i
< hash_size
; i
++)
374 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
375 crecp
&& ((crecp
->flags
& F_REVERSE
) || !(crecp
->flags
& F_IMMORTAL
));
376 crecp
= crecp
->hash_next
)
377 if (is_expired(now
, crecp
))
379 *up
= crecp
->hash_next
;
380 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
386 else if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)) &&
387 (flags
& crecp
->flags
& F_REVERSE
) &&
388 (flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
389 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
391 *up
= crecp
->hash_next
;
396 up
= &crecp
->hash_next
;
402 /* Note: The normal calling sequence is
407 but an abort can cause the cache_end_insert to be missed
408 in which can the next cache_start_insert cleans things up. */
410 void cache_start_insert(void)
412 /* Free any entries which didn't get committed during the last
417 struct crec
*tmp
= new_chain
->next
;
418 cache_free(new_chain
);
425 struct crec
*cache_insert(char *name
, struct all_addr
*addr
,
426 time_t now
, unsigned long ttl
, unsigned short flags
)
429 union bigname
*big_name
= NULL
;
430 int freed_all
= flags
& F_REVERSE
;
433 if (daemon
->max_cache_ttl
!= 0 && daemon
->max_cache_ttl
< ttl
)
434 ttl
= daemon
->max_cache_ttl
;
436 /* Don't log keys here, done elsewhere */
437 if (flags
& (F_IPV4
| F_IPV6
| F_CNAME
))
438 log_query(flags
| F_UPSTREAM
, name
, addr
, NULL
);
440 /* if previous insertion failed give up now. */
444 /* First remove any expired entries and entries for the name/address we
445 are currently inserting. Fail is we attempt to delete a name from
446 /etc/hosts or DHCP. */
447 if (!cache_scan_free(name
, addr
, now
, flags
))
453 /* Now get a cache entry from the end of the LRU list */
455 if (!(new = cache_tail
)) /* no entries left - cache is too small, bail */
461 /* End of LRU list is still in use: if we didn't scan all the hash
462 chains for expired entries do that now. If we already tried that
463 then it's time to start spilling things. */
465 if (new->flags
& (F_FORWARD
| F_REVERSE
))
467 /* If free_avail set, we believe that an entry has been freed.
468 Bugs have been known to make this not true, resulting in
469 a tight loop here. If that happens, abandon the
470 insert. Once in this state, all inserts will probably fail. */
479 free_avail
= 1; /* Must be free space now. */
480 cache_scan_free(cache_get_name(new), &new->addr
.addr
, now
, new->flags
);
485 cache_scan_free(NULL
, NULL
, now
, 0);
491 /* Check if we need to and can allocate extra memory for a long name.
492 If that fails, give up now. */
493 if (name
&& (strlen(name
) > SMALLDNAME
-1))
498 big_free
= big_free
->next
;
500 else if (!bignames_left
||
501 !(big_name
= (union bigname
*)whine_malloc(sizeof(union bigname
))))
511 /* Got the rest: finally grab entry. */
519 new->name
.bname
= big_name
;
520 new->flags
|= F_BIGNAME
;
524 strcpy(cache_get_name(new), name
);
526 *cache_get_name(new) = 0;
529 new->addr
.addr
= *addr
;
531 new->ttd
= now
+ (time_t)ttl
;
532 new->next
= new_chain
;
538 /* after end of insertion, commit the new entries */
539 void cache_end_insert(void)
546 struct crec
*tmp
= new_chain
->next
;
547 /* drop CNAMEs which didn't find a target. */
548 if (is_outdated_cname_pointer(new_chain
))
549 cache_free(new_chain
);
552 cache_hash(new_chain
);
553 cache_link(new_chain
);
561 struct crec
*cache_find_by_name(struct crec
*crecp
, char *name
, time_t now
, unsigned short prot
)
565 if (crecp
) /* iterating */
569 /* first search, look for relevant entries and push to top of list
570 also free anything which has expired */
571 struct crec
*next
, **up
, **insert
= NULL
, **chainp
= &ans
;
572 unsigned short ins_flags
= 0;
574 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= next
)
576 next
= crecp
->hash_next
;
578 if (!is_expired(now
, crecp
) && !is_outdated_cname_pointer(crecp
))
580 if ((crecp
->flags
& F_FORWARD
) &&
582 ((crecp
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
584 (crecp
->flags
& prot
) &&
585 hostname_isequal(cache_get_name(crecp
), name
))
587 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
590 chainp
= &crecp
->next
;
598 /* Move all but the first entry up the hash chain
599 this implements round-robin.
600 Make sure that re-ordering doesn't break the hash-chain
603 if (insert
&& (crecp
->flags
& (F_REVERSE
| F_IMMORTAL
)) == ins_flags
)
605 *up
= crecp
->hash_next
;
606 crecp
->hash_next
= *insert
;
608 insert
= &crecp
->hash_next
;
615 ins_flags
= crecp
->flags
& (F_REVERSE
| F_IMMORTAL
);
617 up
= &crecp
->hash_next
;
621 /* case : not expired, incorrect entry. */
622 up
= &crecp
->hash_next
;
626 /* expired entry, free it */
627 *up
= crecp
->hash_next
;
628 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
636 *chainp
= cache_head
;
640 (ans
->flags
& F_FORWARD
) &&
642 ((ans
->flags
& (F_DNSKEY
| F_DS
)) == (prot
& (F_DNSKEY
| F_DS
))) &&
644 (ans
->flags
& prot
) &&
645 hostname_isequal(cache_get_name(ans
), name
))
651 struct crec
*cache_find_by_addr(struct crec
*crecp
, struct all_addr
*addr
,
652 time_t now
, unsigned short prot
)
656 int addrlen
= (prot
== F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
658 int addrlen
= INADDRSZ
;
661 if (crecp
) /* iterating */
665 /* first search, look for relevant entries and push to top of list
666 also free anything which has expired. All the reverse entries are at the
667 start of the hash chain, so we can give up when we find the first
670 struct crec
**up
, **chainp
= &ans
;
672 for (i
=0; i
<hash_size
; i
++)
673 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
674 crecp
&& (crecp
->flags
& F_REVERSE
);
675 crecp
= crecp
->hash_next
)
676 if (!is_expired(now
, crecp
))
678 if ((crecp
->flags
& prot
) &&
679 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
681 if (crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
))
684 chainp
= &crecp
->next
;
692 up
= &crecp
->hash_next
;
696 *up
= crecp
->hash_next
;
697 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
| F_CONFIG
)))
704 *chainp
= cache_head
;
708 (ans
->flags
& F_REVERSE
) &&
709 (ans
->flags
& prot
) &&
710 memcmp(&ans
->addr
.addr
, addr
, addrlen
) == 0)
716 static void add_hosts_cname(struct crec
*target
)
721 for (a
= daemon
->cnames
; a
; a
= a
->next
)
722 if (hostname_isequal(cache_get_name(target
), a
->target
) &&
723 (crec
= whine_malloc(sizeof(struct crec
))))
725 crec
->flags
= F_FORWARD
| F_IMMORTAL
| F_NAMEP
| F_CONFIG
| F_CNAME
;
726 crec
->name
.namep
= a
->alias
;
727 crec
->addr
.cname
.target
.cache
= target
;
728 crec
->addr
.cname
.uid
= target
->uid
;
730 add_hosts_cname(crec
); /* handle chains */
734 static void add_hosts_entry(struct crec
*cache
, struct all_addr
*addr
, int addrlen
,
735 int index
, struct crec
**rhash
, int hashsz
)
737 struct crec
*lookup
= cache_find_by_name(NULL
, cache_get_name(cache
), 0, cache
->flags
& (F_IPV4
| F_IPV6
));
738 int i
, nameexists
= 0;
741 /* Remove duplicates in hosts files. */
742 if (lookup
&& (lookup
->flags
& F_HOSTS
))
745 if (memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
752 /* Ensure there is only one address -> name mapping (first one trumps)
753 We do this by steam here, The entries are kept in hash chains, linked
754 by ->next (which is unused at this point) held in hash buckets in
755 the array rhash, hashed on address. Note that rhash and the values
756 in ->next are only valid whilst reading hosts files: the buckets are
757 then freed, and the ->next pointer used for other things.
759 Only insert each unique address once into this hashing structure.
761 This complexity avoids O(n^2) divergent CPU use whilst reading
762 large (10000 entry) hosts files. */
765 for (j
= 0, i
= 0; i
< addrlen
; i
++)
766 j
= (j
*2 +((unsigned char *)addr
)[i
]) % hashsz
;
768 for (lookup
= rhash
[j
]; lookup
; lookup
= lookup
->next
)
769 if ((lookup
->flags
& cache
->flags
& (F_IPV4
| F_IPV6
)) &&
770 memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
772 cache
->flags
&= ~F_REVERSE
;
776 /* maintain address hash chain, insert new unique address */
779 cache
->next
= rhash
[j
];
784 memcpy(&cache
->addr
.addr
, addr
, addrlen
);
787 /* don't need to do alias stuff for second and subsequent addresses. */
789 add_hosts_cname(cache
);
792 static int eatspace(FILE *f
)
798 if ((c
= getc(f
)) == '#')
799 while (c
!= '\n' && c
!= EOF
)
816 static int gettok(FILE *f
, char *token
)
822 if ((c
= getc(f
)) == EOF
)
823 return (count
== 0) ? EOF
: 1;
825 if (isspace(c
) || c
== '#')
831 if (count
< (MAXDNAME
- 1))
839 static int read_hostsfile(char *filename
, int index
, int cache_size
, struct crec
**rhash
, int hashsz
)
841 FILE *f
= fopen(filename
, "r");
842 char *token
= daemon
->namebuff
, *domain_suffix
= NULL
;
843 int addr_count
= 0, name_count
= cache_size
, lineno
= 0;
844 unsigned short flags
= 0;
845 struct all_addr addr
;
846 int atnl
, addrlen
= 0;
850 my_syslog(LOG_ERR
, _("failed to load names from %s: %s"), filename
, strerror(errno
));
856 while ((atnl
= gettok(f
, token
)) != EOF
)
860 if (inet_pton(AF_INET
, token
, &addr
) > 0)
862 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
;
864 domain_suffix
= get_domain(addr
.addr
.addr4
);
867 else if (inet_pton(AF_INET6
, token
, &addr
) > 0)
869 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
;
871 domain_suffix
= get_domain6(&addr
.addr
.addr6
);
876 my_syslog(LOG_ERR
, _("bad address at %s line %d"), filename
, lineno
);
878 atnl
= gettok(f
, token
);
884 /* rehash every 1000 names. */
885 if ((name_count
- cache_size
) > 1000)
888 cache_size
= name_count
;
897 if ((atnl
= gettok(f
, token
)) == EOF
)
900 fqdn
= !!strchr(token
, '.');
902 if ((canon
= canonicalise(token
, &nomem
)))
904 /* If set, add a version of the name with a default domain appended */
905 if (option_bool(OPT_EXPAND
) && domain_suffix
&& !fqdn
&&
906 (cache
= whine_malloc(sizeof(struct crec
) +
907 strlen(canon
)+2+strlen(domain_suffix
)-SMALLDNAME
)))
909 strcpy(cache
->name
.sname
, canon
);
910 strcat(cache
->name
.sname
, ".");
911 strcat(cache
->name
.sname
, domain_suffix
);
912 cache
->flags
= flags
;
913 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
916 if ((cache
= whine_malloc(sizeof(struct crec
) + strlen(canon
)+1-SMALLDNAME
)))
918 strcpy(cache
->name
.sname
, canon
);
919 cache
->flags
= flags
;
920 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
927 my_syslog(LOG_ERR
, _("bad name at %s line %d"), filename
, lineno
);
934 my_syslog(LOG_INFO
, _("read %s - %d addresses"), filename
, addr_count
);
939 void cache_reload(void)
941 struct crec
*cache
, **up
, *tmp
;
942 int revhashsz
, i
, total_size
= daemon
->cachesize
;
943 struct hostsfile
*ah
;
944 struct host_record
*hr
;
945 struct name_list
*nl
;
947 struct interface_name
*intr
;
952 cache_inserted
= cache_live_freed
= 0;
954 for (i
=0; i
<hash_size
; i
++)
955 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= tmp
)
958 if (cache
->flags
& (F_DNSKEY
| F_DS
))
959 blockdata_free(cache
->addr
.key
.keydata
);
961 tmp
= cache
->hash_next
;
962 if (cache
->flags
& (F_HOSTS
| F_CONFIG
))
964 *up
= cache
->hash_next
;
967 else if (!(cache
->flags
& F_DHCP
))
969 *up
= cache
->hash_next
;
970 if (cache
->flags
& F_BIGNAME
)
972 cache
->name
.bname
->next
= big_free
;
973 big_free
= cache
->name
.bname
;
978 up
= &cache
->hash_next
;
981 /* Add CNAMEs to interface_names to the cache */
982 for (a
= daemon
->cnames
; a
; a
= a
->next
)
983 for (intr
= daemon
->int_names
; intr
; intr
= intr
->next
)
984 if (hostname_isequal(a
->target
, intr
->name
) &&
985 ((cache
= whine_malloc(sizeof(struct crec
)))))
987 cache
->flags
= F_FORWARD
| F_NAMEP
| F_CNAME
| F_IMMORTAL
| F_CONFIG
;
988 cache
->name
.namep
= a
->alias
;
989 cache
->addr
.cname
.target
.int_name
= intr
;
990 cache
->addr
.cname
.uid
= -1;
992 add_hosts_cname(cache
); /* handle chains */
996 for (key
= daemon
->dnskeys
; key
; key
= key
->next
)
997 if ((cache
= whine_malloc(sizeof(struct crec
))) &&
998 (cache
->addr
.key
.keydata
= blockdata_alloc(key
->key
, key
->keylen
)))
1000 cache
->flags
= F_FORWARD
| F_IMMORTAL
| F_DNSKEY
| F_CONFIG
| F_NAMEP
;
1001 cache
->name
.namep
= key
->name
;
1002 cache
->addr
.key
.keylen
= key
->keylen
;
1003 cache
->addr
.key
.algo
= key
->algo
;
1004 cache
->addr
.key
.flags
= key
->flags
;
1005 cache
->addr
.key
.keytag
= dnskey_keytag(key
->algo
, key
->flags
, (unsigned char *)key
->key
, key
->keylen
);
1006 cache
->uid
= C_IN
; /* TODO - in option? */
1011 /* borrow the packet buffer for a temporary by-address hash */
1012 memset(daemon
->packet
, 0, daemon
->packet_buff_sz
);
1013 revhashsz
= daemon
->packet_buff_sz
/ sizeof(struct crec
*);
1014 /* we overwrote the buffer... */
1015 daemon
->srv_save
= NULL
;
1017 /* Do host_records in config. */
1018 for (hr
= daemon
->host_records
; hr
; hr
= hr
->next
)
1019 for (nl
= hr
->names
; nl
; nl
= nl
->next
)
1021 if (hr
->addr
.s_addr
!= 0 &&
1022 (cache
= whine_malloc(sizeof(struct crec
))))
1024 cache
->name
.namep
= nl
->name
;
1025 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_NAMEP
| F_CONFIG
;
1026 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr
, INADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1029 if (!IN6_IS_ADDR_UNSPECIFIED(&hr
->addr6
) &&
1030 (cache
= whine_malloc(sizeof(struct crec
))))
1032 cache
->name
.namep
= nl
->name
;
1033 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_NAMEP
| F_CONFIG
;
1034 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr6
, IN6ADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
1039 if (option_bool(OPT_NO_HOSTS
) && !daemon
->addn_hosts
)
1041 if (daemon
->cachesize
> 0)
1042 my_syslog(LOG_INFO
, _("cleared cache"));
1046 if (!option_bool(OPT_NO_HOSTS
))
1047 total_size
= read_hostsfile(HOSTSFILE
, 0, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1049 daemon
->addn_hosts
= expand_filelist(daemon
->addn_hosts
);
1050 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1051 if (!(ah
->flags
& AH_INACTIVE
))
1052 total_size
= read_hostsfile(ah
->fname
, ah
->index
, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
1056 struct in_addr
a_record_from_hosts(char *name
, time_t now
)
1058 struct crec
*crecp
= NULL
;
1061 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
1062 if (crecp
->flags
& F_HOSTS
)
1063 return *(struct in_addr
*)&crecp
->addr
;
1065 my_syslog(MS_DHCP
| LOG_WARNING
, _("No IPv4 address found for %s"), name
);
1071 void cache_unhash_dhcp(void)
1073 struct crec
*cache
, **up
;
1076 for (i
=0; i
<hash_size
; i
++)
1077 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1078 if (cache
->flags
& F_DHCP
)
1080 *up
= cache
->hash_next
;
1081 cache
->next
= dhcp_spare
;
1085 up
= &cache
->hash_next
;
1088 static void add_dhcp_cname(struct crec
*target
, time_t ttd
)
1090 struct crec
*aliasc
;
1093 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1094 if (hostname_isequal(cache_get_name(target
), a
->target
))
1096 if ((aliasc
= dhcp_spare
))
1097 dhcp_spare
= dhcp_spare
->next
;
1098 else /* need new one */
1099 aliasc
= whine_malloc(sizeof(struct crec
));
1103 aliasc
->flags
= F_FORWARD
| F_NAMEP
| F_DHCP
| F_CNAME
| F_CONFIG
;
1105 aliasc
->flags
|= F_IMMORTAL
;
1108 aliasc
->name
.namep
= a
->alias
;
1109 aliasc
->addr
.cname
.target
.cache
= target
;
1110 aliasc
->addr
.cname
.uid
= target
->uid
;
1112 add_dhcp_cname(aliasc
, ttd
);
1117 void cache_add_dhcp_entry(char *host_name
, int prot
,
1118 struct all_addr
*host_address
, time_t ttd
)
1120 struct crec
*crec
= NULL
, *fail_crec
= NULL
;
1121 unsigned short flags
= F_IPV4
;
1123 size_t addrlen
= sizeof(struct in_addr
);
1126 if (prot
== AF_INET6
)
1129 addrlen
= sizeof(struct in6_addr
);
1133 inet_ntop(prot
, host_address
, daemon
->addrbuff
, ADDRSTRLEN
);
1135 while ((crec
= cache_find_by_name(crec
, host_name
, 0, flags
| F_CNAME
)))
1137 /* check all addresses associated with name */
1138 if (crec
->flags
& (F_HOSTS
| F_CONFIG
))
1140 if (crec
->flags
& F_CNAME
)
1141 my_syslog(MS_DHCP
| LOG_WARNING
,
1142 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1143 host_name
, daemon
->addrbuff
);
1144 else if (memcmp(&crec
->addr
.addr
, host_address
, addrlen
) == 0)
1149 else if (!(crec
->flags
& F_DHCP
))
1151 cache_scan_free(host_name
, NULL
, 0, crec
->flags
& (flags
| F_CNAME
| F_FORWARD
));
1152 /* scan_free deletes all addresses associated with name */
1157 /* if in hosts, don't need DHCP record */
1161 /* Name in hosts, address doesn't match */
1164 inet_ntop(prot
, &fail_crec
->addr
.addr
, daemon
->namebuff
, MAXDNAME
);
1165 my_syslog(MS_DHCP
| LOG_WARNING
,
1166 _("not giving name %s to the DHCP lease of %s because "
1167 "the name exists in %s with address %s"),
1168 host_name
, daemon
->addrbuff
,
1169 record_source(fail_crec
->uid
), daemon
->namebuff
);
1173 if ((crec
= cache_find_by_addr(NULL
, (struct all_addr
*)host_address
, 0, flags
)))
1175 if (crec
->flags
& F_NEG
)
1178 cache_scan_free(NULL
, (struct all_addr
*)host_address
, 0, flags
);
1184 if ((crec
= dhcp_spare
))
1185 dhcp_spare
= dhcp_spare
->next
;
1186 else /* need new one */
1187 crec
= whine_malloc(sizeof(struct crec
));
1189 if (crec
) /* malloc may fail */
1191 crec
->flags
= flags
| F_NAMEP
| F_DHCP
| F_FORWARD
;
1193 crec
->flags
|= F_IMMORTAL
;
1196 crec
->addr
.addr
= *host_address
;
1197 crec
->name
.namep
= host_name
;
1201 add_dhcp_cname(crec
, ttd
);
1207 void dump_cache(time_t now
)
1209 struct server
*serv
, *serv1
;
1212 my_syslog(LOG_INFO
, _("time %lu"), (unsigned long)now
);
1213 my_syslog(LOG_INFO
, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1214 daemon
->cachesize
, cache_live_freed
, cache_inserted
);
1215 my_syslog(LOG_INFO
, _("queries forwarded %u, queries answered locally %u"),
1216 daemon
->queries_forwarded
, daemon
->local_answer
);
1218 my_syslog(LOG_INFO
, _("queries for authoritative zones %u"), daemon
->auth_answer
);
1224 /* sum counts from different records for same server */
1225 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1226 serv
->flags
&= ~SERV_COUNTED
;
1228 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1230 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)))
1233 unsigned int queries
= 0, failed_queries
= 0;
1234 for (serv1
= serv
; serv1
; serv1
= serv1
->next
)
1235 if (!(serv1
->flags
&
1236 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)) &&
1237 sockaddr_isequal(&serv
->addr
, &serv1
->addr
))
1239 serv1
->flags
|= SERV_COUNTED
;
1240 queries
+= serv1
->queries
;
1241 failed_queries
+= serv1
->failed_queries
;
1243 port
= prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
1244 my_syslog(LOG_INFO
, _("server %s#%d: queries sent %u, retried or failed %u"), daemon
->addrbuff
, port
, queries
, failed_queries
);
1247 if (option_bool(OPT_DEBUG
) || option_bool(OPT_LOG
))
1249 struct crec
*cache
;
1251 my_syslog(LOG_INFO
, "Host Address Flags Expires");
1253 for (i
=0; i
<hash_size
; i
++)
1254 for (cache
= hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1256 char *a
= daemon
->addrbuff
, *p
= daemon
->namebuff
, *n
= cache_get_name(cache
);
1260 p
+= sprintf(p
, "%-40.40s ", n
);
1261 if ((cache
->flags
& F_CNAME
) && !is_outdated_cname_pointer(cache
))
1262 a
= cache_get_cname_target(cache
);
1264 else if (cache
->flags
& F_DS
)
1266 if (cache
->flags
& F_DNSKEY
)
1270 querystr("", tp
, cache
->addr
.sig
.type_covered
);
1271 a
= daemon
->addrbuff
;
1272 sprintf(a
, "%5u %3u %s", cache
->addr
.sig
.keytag
,
1273 cache
->addr
.sig
.algo
, tp
);
1277 a
= daemon
->addrbuff
;
1278 sprintf(a
, "%5u %3u %3u", cache
->addr
.ds
.keytag
,
1279 cache
->addr
.ds
.algo
, cache
->addr
.ds
.digest
);
1282 else if (cache
->flags
& F_DNSKEY
)
1284 a
= daemon
->addrbuff
;
1285 sprintf(a
, "%5u %3u %3u", cache
->addr
.key
.keytag
,
1286 cache
->addr
.key
.algo
, cache
->addr
.key
.flags
);
1289 else if (!(cache
->flags
& F_NEG
) || !(cache
->flags
& F_FORWARD
))
1291 a
= daemon
->addrbuff
;
1292 if (cache
->flags
& F_IPV4
)
1293 inet_ntop(AF_INET
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1295 else if (cache
->flags
& F_IPV6
)
1296 inet_ntop(AF_INET6
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1300 if (cache
->flags
& F_IPV4
)
1302 else if (cache
->flags
& F_IPV6
)
1304 else if (cache
->flags
& F_CNAME
)
1307 else if ((cache
->flags
& (F_DS
| F_DNSKEY
)) == (F_DS
| F_DNSKEY
))
1308 t
= "G"; /* DNSKEY and DS set -> RRISG */
1309 else if (cache
->flags
& F_DS
)
1311 else if (cache
->flags
& F_DNSKEY
)
1314 p
+= sprintf(p
, "%-30.30s %s%s%s%s%s%s%s%s%s ", a
, t
,
1315 cache
->flags
& F_FORWARD
? "F" : " ",
1316 cache
->flags
& F_REVERSE
? "R" : " ",
1317 cache
->flags
& F_IMMORTAL
? "I" : " ",
1318 cache
->flags
& F_DHCP
? "D" : " ",
1319 cache
->flags
& F_NEG
? "N" : " ",
1320 cache
->flags
& F_NXDOMAIN
? "X" : " ",
1321 cache
->flags
& F_HOSTS
? "H" : " ",
1322 cache
->flags
& F_DNSSECOK
? "V" : " ");
1323 #ifdef HAVE_BROKEN_RTC
1324 p
+= sprintf(p
, "%lu", cache
->flags
& F_IMMORTAL
? 0: (unsigned long)(cache
->ttd
- now
));
1326 p
+= sprintf(p
, "%s", cache
->flags
& F_IMMORTAL
? "\n" : ctime(&(cache
->ttd
)));
1327 /* ctime includes trailing \n - eat it */
1330 my_syslog(LOG_INFO
, daemon
->namebuff
);
1335 char *record_source(int index
)
1337 struct hostsfile
*ah
;
1342 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1343 if (ah
->index
== index
)
1349 void querystr(char *desc
, char *str
, unsigned short type
)
1353 sprintf(str
, "%s[type=%d]", desc
, type
);
1354 for (i
= 0; i
< (sizeof(typestr
)/sizeof(typestr
[0])); i
++)
1355 if (typestr
[i
].type
== type
)
1356 sprintf(str
,"%s[%s]", desc
, typestr
[i
].name
);
1359 void log_query(unsigned int flags
, char *name
, struct all_addr
*addr
, char *arg
)
1361 char *source
, *dest
= daemon
->addrbuff
;
1364 if (!option_bool(OPT_LOG
))
1369 if (flags
& F_KEYTAG
)
1370 sprintf(daemon
->addrbuff
, arg
, addr
->addr
.keytag
);
1374 inet_ntop(flags
& F_IPV4
? AF_INET
: AF_INET6
,
1375 addr
, daemon
->addrbuff
, ADDRSTRLEN
);
1377 strncpy(daemon
->addrbuff
, inet_ntoa(addr
->addr
.addr4
), ADDRSTRLEN
);
1384 if (flags
& F_REVERSE
)
1387 name
= daemon
->addrbuff
;
1392 if (flags
& F_NXDOMAIN
)
1395 dest
= "NXDOMAIN-IPv4";
1396 else if (flags
& F_IPV6
)
1397 dest
= "NXDOMAIN-IPv6";
1404 dest
= "NODATA-IPv4";
1405 else if (flags
& F_IPV6
)
1406 dest
= "NODATA-IPv6";
1411 else if (flags
& F_CNAME
)
1413 else if (flags
& F_RRNAME
)
1416 if (flags
& F_CONFIG
)
1418 else if (flags
& F_DHCP
)
1420 else if (flags
& F_HOSTS
)
1422 else if (flags
& F_UPSTREAM
)
1424 else if (flags
& F_SECSTAT
)
1425 source
= "validation";
1426 else if (flags
& F_AUTH
)
1428 else if (flags
& F_SERVER
)
1430 source
= "forwarded";
1433 else if (flags
& F_QUERY
)
1438 else if (flags
& F_DNSSEC
)
1446 if (strlen(name
) == 0)
1449 my_syslog(LOG_INFO
, "%s %s %s %s", source
, name
, verb
, dest
);