]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
1 /* dnsmasq is Copyright (c) 2000-2013 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 static struct keydata
*keyblock_free
= NULL
;
32 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
35 const char * const name
;
69 static void cache_free(struct crec
*crecp
);
70 static void cache_unlink(struct crec
*crecp
);
71 static void cache_link(struct crec
*crecp
);
72 static void rehash(int size
);
73 static void cache_hash(struct crec
*crecp
);
80 bignames_left
= daemon
->cachesize
/10;
82 if (daemon
->cachesize
> 0)
84 crecp
= safe_malloc(daemon
->cachesize
*sizeof(struct crec
));
86 for (i
=0; i
< daemon
->cachesize
; i
++, crecp
++)
94 /* create initial hash table*/
95 rehash(daemon
->cachesize
);
98 /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
99 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
100 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
102 static void rehash(int size
)
104 struct crec
**new, **old
, *p
, *tmp
;
105 int i
, new_size
, old_size
;
107 /* hash_size is a power of two. */
108 for (new_size
= 64; new_size
< size
/10; new_size
= new_size
<< 1);
110 /* must succeed in getting first instance, failure later is non-fatal */
112 new = safe_malloc(new_size
* sizeof(struct crec
*));
113 else if (new_size
<= hash_size
|| !(new = whine_malloc(new_size
* sizeof(struct crec
*))))
116 for(i
= 0; i
< new_size
; i
++)
120 old_size
= hash_size
;
122 hash_size
= new_size
;
126 for (i
= 0; i
< old_size
; i
++)
127 for (p
= old
[i
]; p
; p
= tmp
)
136 static struct crec
**hash_bucket(char *name
)
138 unsigned int c
, val
= 017465; /* Barker code - minimum self-correlation in cyclic shift */
139 const unsigned char *mix_tab
= (const unsigned char*)typestr
;
141 while((c
= (unsigned char) *name
++))
143 /* don't use tolower and friends here - they may be messed up by LOCALE */
144 if (c
>= 'A' && c
<= 'Z')
146 val
= ((val
<< 7) | (val
>> (32 - 7))) + (mix_tab
[(val
+ c
) & 0x3F] ^ c
);
149 /* hash_size is a power of two */
150 return hash_table
+ ((val
^ (val
>> 16)) & (hash_size
- 1));
153 static void cache_hash(struct crec
*crecp
)
155 /* maintain an invariant that all entries with F_REVERSE set
156 are at the start of the hash-chain and all non-reverse
157 immortal entries are at the end of the hash-chain.
158 This allows reverse searches and garbage collection to be optimised */
160 struct crec
**up
= hash_bucket(cache_get_name(crecp
));
162 if (!(crecp
->flags
& F_REVERSE
))
164 while (*up
&& ((*up
)->flags
& F_REVERSE
))
165 up
= &((*up
)->hash_next
);
167 if (crecp
->flags
& F_IMMORTAL
)
168 while (*up
&& !((*up
)->flags
& F_IMMORTAL
))
169 up
= &((*up
)->hash_next
);
171 crecp
->hash_next
= *up
;
175 static void cache_free(struct crec
*crecp
)
177 crecp
->flags
&= ~F_FORWARD
;
178 crecp
->flags
&= ~F_REVERSE
;
179 crecp
->uid
= uid
++; /* invalidate CNAMES pointing to this. */
182 cache_tail
->next
= crecp
;
185 crecp
->prev
= cache_tail
;
189 /* retrieve big name for further use. */
190 if (crecp
->flags
& F_BIGNAME
)
192 crecp
->name
.bname
->next
= big_free
;
193 big_free
= crecp
->name
.bname
;
194 crecp
->flags
&= ~F_BIGNAME
;
197 else if (crecp
->flags
& (F_DNSKEY
| F_DS
))
198 keydata_free(crecp
->addr
.key
.keydata
);
202 /* insert a new cache entry at the head of the list (youngest entry) */
203 static void cache_link(struct crec
*crecp
)
205 if (cache_head
) /* check needed for init code */
206 cache_head
->prev
= crecp
;
207 crecp
->next
= cache_head
;
214 /* remove an arbitrary cache entry for promotion */
215 static void cache_unlink (struct crec
*crecp
)
218 crecp
->prev
->next
= crecp
->next
;
220 cache_head
= crecp
->next
;
223 crecp
->next
->prev
= crecp
->prev
;
225 cache_tail
= crecp
->prev
;
228 char *cache_get_name(struct crec
*crecp
)
230 if (crecp
->flags
& F_BIGNAME
)
231 return crecp
->name
.bname
->name
;
232 else if (crecp
->flags
& F_NAMEP
)
233 return crecp
->name
.namep
;
235 return crecp
->name
.sname
;
238 struct crec
*cache_enumerate(int init
)
241 static struct crec
*cache
;
248 else if (cache
&& cache
->hash_next
)
249 cache
= cache
->hash_next
;
253 while (bucket
< hash_size
)
254 if ((cache
= hash_table
[bucket
++]))
261 static int is_outdated_cname_pointer(struct crec
*crecp
)
263 if (!(crecp
->flags
& F_CNAME
))
266 /* NB. record may be reused as DS or DNSKEY, where uid is
267 overloaded for something completely different */
268 if (crecp
->addr
.cname
.cache
&&
269 (crecp
->addr
.cname
.cache
->flags
& (F_IPV4
| F_IPV6
| F_CNAME
)) &&
270 crecp
->addr
.cname
.uid
== crecp
->addr
.cname
.cache
->uid
)
276 static int is_expired(time_t now
, struct crec
*crecp
)
278 if (crecp
->flags
& F_IMMORTAL
)
281 if (difftime(now
, crecp
->ttd
) < 0)
287 static int cache_scan_free(char *name
, struct all_addr
*addr
, time_t now
, unsigned short flags
)
289 /* Scan and remove old entries.
290 If (flags & F_FORWARD) then remove any forward entries for name and any expired
291 entries but only in the same hash bucket as name.
292 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
293 entries in the whole cache.
294 If (flags == 0) remove any expired entries in the whole cache.
296 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
297 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
299 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
300 so that when we hit an entry which isn't reverse and is immortal, we're done. */
302 struct crec
*crecp
, **up
;
304 if (flags
& F_FORWARD
)
306 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= crecp
->hash_next
)
307 if (is_expired(now
, crecp
) || is_outdated_cname_pointer(crecp
))
309 *up
= crecp
->hash_next
;
310 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
316 else if ((crecp
->flags
& F_FORWARD
) &&
317 ((flags
& crecp
->flags
& F_TYPE
) || ((crecp
->flags
| flags
) & F_CNAME
)) &&
318 hostname_isequal(cache_get_name(crecp
), name
))
320 if (crecp
->flags
& (F_HOSTS
| F_DHCP
))
322 *up
= crecp
->hash_next
;
327 up
= &crecp
->hash_next
;
333 int addrlen
= (flags
& F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
335 int addrlen
= INADDRSZ
;
337 for (i
= 0; i
< hash_size
; i
++)
338 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
339 crecp
&& ((crecp
->flags
& F_REVERSE
) || !(crecp
->flags
& F_IMMORTAL
));
340 crecp
= crecp
->hash_next
)
341 if (is_expired(now
, crecp
))
343 *up
= crecp
->hash_next
;
344 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
350 else if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)) &&
351 (flags
& crecp
->flags
& F_REVERSE
) &&
352 (flags
& crecp
->flags
& (F_IPV4
| F_IPV6
)) &&
353 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
355 *up
= crecp
->hash_next
;
360 up
= &crecp
->hash_next
;
366 /* Note: The normal calling sequence is
371 but an abort can cause the cache_end_insert to be missed
372 in which can the next cache_start_insert cleans things up. */
374 void cache_start_insert(void)
376 /* Free any entries which didn't get committed during the last
381 struct crec
*tmp
= new_chain
->next
;
382 cache_free(new_chain
);
389 struct crec
*cache_insert(char *name
, struct all_addr
*addr
,
390 time_t now
, unsigned long ttl
, unsigned short flags
)
393 union bigname
*big_name
= NULL
;
394 int freed_all
= flags
& F_REVERSE
;
397 if (daemon
->max_cache_ttl
!= 0 && daemon
->max_cache_ttl
< ttl
)
398 ttl
= daemon
->max_cache_ttl
;
401 if (flags
& (F_IPV4
| F_IPV6
))
402 log_query(flags
| F_UPSTREAM
, name
, addr
, NULL
);
404 /* if previous insertion failed give up now. */
408 /* First remove any expired entries and entries for the name/address we
409 are currently inserting. Fail is we attempt to delete a name from
410 /etc/hosts or DHCP. */
411 if (!cache_scan_free(name
, addr
, now
, flags
))
417 /* Now get a cache entry from the end of the LRU list */
419 if (!(new = cache_tail
)) /* no entries left - cache is too small, bail */
425 /* End of LRU list is still in use: if we didn't scan all the hash
426 chains for expired entries do that now. If we already tried that
427 then it's time to start spilling things. */
429 if (new->flags
& (F_FORWARD
| F_REVERSE
))
431 /* If free_avail set, we believe that an entry has been freed.
432 Bugs have been known to make this not true, resulting in
433 a tight loop here. If that happens, abandon the
434 insert. Once in this state, all inserts will probably fail. */
443 free_avail
= 1; /* Must be free space now. */
444 cache_scan_free(cache_get_name(new), &new->addr
.addr
, now
, new->flags
);
449 cache_scan_free(NULL
, NULL
, now
, 0);
455 /* Check if we need to and can allocate extra memory for a long name.
456 If that fails, give up now. */
457 if (name
&& (strlen(name
) > SMALLDNAME
-1))
462 big_free
= big_free
->next
;
464 else if (!bignames_left
||
465 !(big_name
= (union bigname
*)whine_malloc(sizeof(union bigname
))))
475 /* Got the rest: finally grab entry. */
483 new->name
.bname
= big_name
;
484 new->flags
|= F_BIGNAME
;
488 strcpy(cache_get_name(new), name
);
490 *cache_get_name(new) = 0;
493 new->addr
.addr
= *addr
;
495 new->ttd
= now
+ (time_t)ttl
;
496 new->next
= new_chain
;
502 /* after end of insertion, commit the new entries */
503 void cache_end_insert(void)
510 struct crec
*tmp
= new_chain
->next
;
511 /* drop CNAMEs which didn't find a target. */
512 if (is_outdated_cname_pointer(new_chain
))
513 cache_free(new_chain
);
516 cache_hash(new_chain
);
517 cache_link(new_chain
);
525 struct crec
*cache_find_by_name(struct crec
*crecp
, char *name
, time_t now
, unsigned short prot
)
529 if (crecp
) /* iterating */
533 /* first search, look for relevant entries and push to top of list
534 also free anything which has expired */
535 struct crec
*next
, **up
, **insert
= NULL
, **chainp
= &ans
;
536 unsigned short ins_flags
= 0;
538 for (up
= hash_bucket(name
), crecp
= *up
; crecp
; crecp
= next
)
540 next
= crecp
->hash_next
;
542 if (!is_expired(now
, crecp
) && !is_outdated_cname_pointer(crecp
))
544 if ((crecp
->flags
& F_FORWARD
) &&
545 (crecp
->flags
& prot
) &&
546 hostname_isequal(cache_get_name(crecp
), name
))
548 if (crecp
->flags
& (F_HOSTS
| F_DHCP
))
551 chainp
= &crecp
->next
;
559 /* Move all but the first entry up the hash chain
560 this implements round-robin.
561 Make sure that re-ordering doesn't break the hash-chain
564 if (insert
&& (crecp
->flags
& (F_REVERSE
| F_IMMORTAL
)) == ins_flags
)
566 *up
= crecp
->hash_next
;
567 crecp
->hash_next
= *insert
;
569 insert
= &crecp
->hash_next
;
576 ins_flags
= crecp
->flags
& (F_REVERSE
| F_IMMORTAL
);
578 up
= &crecp
->hash_next
;
582 /* case : not expired, incorrect entry. */
583 up
= &crecp
->hash_next
;
587 /* expired entry, free it */
588 *up
= crecp
->hash_next
;
589 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
597 *chainp
= cache_head
;
601 (ans
->flags
& F_FORWARD
) &&
602 (ans
->flags
& prot
) &&
603 hostname_isequal(cache_get_name(ans
), name
))
609 struct crec
*cache_find_by_addr(struct crec
*crecp
, struct all_addr
*addr
,
610 time_t now
, unsigned short prot
)
614 int addrlen
= (prot
== F_IPV6
) ? IN6ADDRSZ
: INADDRSZ
;
616 int addrlen
= INADDRSZ
;
619 if (crecp
) /* iterating */
623 /* first search, look for relevant entries and push to top of list
624 also free anything which has expired. All the reverse entries are at the
625 start of the hash chain, so we can give up when we find the first
628 struct crec
**up
, **chainp
= &ans
;
630 for (i
=0; i
<hash_size
; i
++)
631 for (crecp
= hash_table
[i
], up
= &hash_table
[i
];
632 crecp
&& (crecp
->flags
& F_REVERSE
);
633 crecp
= crecp
->hash_next
)
634 if (!is_expired(now
, crecp
))
636 if ((crecp
->flags
& prot
) &&
637 memcmp(&crecp
->addr
.addr
, addr
, addrlen
) == 0)
639 if (crecp
->flags
& (F_HOSTS
| F_DHCP
))
642 chainp
= &crecp
->next
;
650 up
= &crecp
->hash_next
;
654 *up
= crecp
->hash_next
;
655 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
662 *chainp
= cache_head
;
666 (ans
->flags
& F_REVERSE
) &&
667 (ans
->flags
& prot
) &&
668 memcmp(&ans
->addr
.addr
, addr
, addrlen
) == 0)
674 static void add_hosts_cname(struct crec
*target
)
679 for (a
= daemon
->cnames
; a
; a
= a
->next
)
680 if (hostname_isequal(cache_get_name(target
), a
->target
) &&
681 (crec
= whine_malloc(sizeof(struct crec
))))
683 crec
->flags
= F_FORWARD
| F_IMMORTAL
| F_NAMEP
| F_HOSTS
| F_CNAME
;
684 crec
->name
.namep
= a
->alias
;
685 crec
->addr
.cname
.cache
= target
;
686 crec
->addr
.cname
.uid
= target
->uid
;
688 add_hosts_cname(crec
); /* handle chains */
692 static void add_hosts_entry(struct crec
*cache
, struct all_addr
*addr
, int addrlen
,
693 int index
, struct crec
**rhash
, int hashsz
)
695 struct crec
*lookup
= cache_find_by_name(NULL
, cache_get_name(cache
), 0, cache
->flags
& (F_IPV4
| F_IPV6
));
696 int i
, nameexists
= 0;
699 /* Remove duplicates in hosts files. */
700 if (lookup
&& (lookup
->flags
& F_HOSTS
))
703 if (memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
710 /* Ensure there is only one address -> name mapping (first one trumps)
711 We do this by steam here, The entries are kept in hash chains, linked
712 by ->next (which is unused at this point) held in hash buckets in
713 the array rhash, hashed on address. Note that rhash and the values
714 in ->next are only valid whilst reading hosts files: the buckets are
715 then freed, and the ->next pointer used for other things.
717 Only insert each unique address once into this hashing structure.
719 This complexity avoids O(n^2) divergent CPU use whilst reading
720 large (10000 entry) hosts files. */
723 for (j
= 0, i
= 0; i
< addrlen
; i
++)
724 j
= (j
*2 +((unsigned char *)addr
)[i
]) % hashsz
;
726 for (lookup
= rhash
[j
]; lookup
; lookup
= lookup
->next
)
727 if ((lookup
->flags
& cache
->flags
& (F_IPV4
| F_IPV6
)) &&
728 memcmp(&lookup
->addr
.addr
, addr
, addrlen
) == 0)
730 cache
->flags
&= ~F_REVERSE
;
734 /* maintain address hash chain, insert new unique address */
737 cache
->next
= rhash
[j
];
742 memcpy(&cache
->addr
.addr
, addr
, addrlen
);
745 /* don't need to do alias stuff for second and subsequent addresses. */
747 add_hosts_cname(cache
);
750 static int eatspace(FILE *f
)
756 if ((c
= getc(f
)) == '#')
757 while (c
!= '\n' && c
!= EOF
)
774 static int gettok(FILE *f
, char *token
)
780 if ((c
= getc(f
)) == EOF
)
781 return (count
== 0) ? EOF
: 1;
783 if (isspace(c
) || c
== '#')
789 if (count
< (MAXDNAME
- 1))
797 static int read_hostsfile(char *filename
, int index
, int cache_size
, struct crec
**rhash
, int hashsz
)
799 FILE *f
= fopen(filename
, "r");
800 char *token
= daemon
->namebuff
, *domain_suffix
= NULL
;
801 int addr_count
= 0, name_count
= cache_size
, lineno
= 0;
802 unsigned short flags
= 0;
803 struct all_addr addr
;
804 int atnl
, addrlen
= 0;
808 my_syslog(LOG_ERR
, _("failed to load names from %s: %s"), filename
, strerror(errno
));
814 while ((atnl
= gettok(f
, token
)) != EOF
)
818 if (inet_pton(AF_INET
, token
, &addr
) > 0)
820 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
;
822 domain_suffix
= get_domain(addr
.addr
.addr4
);
825 else if (inet_pton(AF_INET6
, token
, &addr
) > 0)
827 flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
;
829 domain_suffix
= get_domain6(&addr
.addr
.addr6
);
834 my_syslog(LOG_ERR
, _("bad address at %s line %d"), filename
, lineno
);
836 atnl
= gettok(f
, token
);
842 /* rehash every 1000 names. */
843 if ((name_count
- cache_size
) > 1000)
846 cache_size
= name_count
;
855 if ((atnl
= gettok(f
, token
)) == EOF
)
858 fqdn
= !!strchr(token
, '.');
860 if ((canon
= canonicalise(token
, &nomem
)))
862 /* If set, add a version of the name with a default domain appended */
863 if (option_bool(OPT_EXPAND
) && domain_suffix
&& !fqdn
&&
864 (cache
= whine_malloc(sizeof(struct crec
) +
865 strlen(canon
)+2+strlen(domain_suffix
)-SMALLDNAME
)))
867 strcpy(cache
->name
.sname
, canon
);
868 strcat(cache
->name
.sname
, ".");
869 strcat(cache
->name
.sname
, domain_suffix
);
870 cache
->flags
= flags
;
871 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
874 if ((cache
= whine_malloc(sizeof(struct crec
) + strlen(canon
)+1-SMALLDNAME
)))
876 strcpy(cache
->name
.sname
, canon
);
877 cache
->flags
= flags
;
878 add_hosts_entry(cache
, &addr
, addrlen
, index
, rhash
, hashsz
);
885 my_syslog(LOG_ERR
, _("bad name at %s line %d"), filename
, lineno
);
892 my_syslog(LOG_INFO
, _("read %s - %d addresses"), filename
, addr_count
);
897 void cache_reload(void)
899 struct crec
*cache
, **up
, *tmp
;
900 int revhashsz
, i
, total_size
= daemon
->cachesize
;
901 struct hostsfile
*ah
;
902 struct host_record
*hr
;
903 struct name_list
*nl
;
905 cache_inserted
= cache_live_freed
= 0;
907 for (i
=0; i
<hash_size
; i
++)
908 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= tmp
)
910 tmp
= cache
->hash_next
;
911 if (cache
->flags
& F_HOSTS
)
913 *up
= cache
->hash_next
;
916 else if (!(cache
->flags
& F_DHCP
))
918 *up
= cache
->hash_next
;
919 if (cache
->flags
& F_BIGNAME
)
921 cache
->name
.bname
->next
= big_free
;
922 big_free
= cache
->name
.bname
;
927 up
= &cache
->hash_next
;
930 /* borrow the packet buffer for a temporary by-address hash */
931 memset(daemon
->packet
, 0, daemon
->packet_buff_sz
);
932 revhashsz
= daemon
->packet_buff_sz
/ sizeof(struct crec
*);
933 /* we overwrote the buffer... */
934 daemon
->srv_save
= NULL
;
936 /* Do host_records in config. */
937 for (hr
= daemon
->host_records
; hr
; hr
= hr
->next
)
938 for (nl
= hr
->names
; nl
; nl
= nl
->next
)
940 if (hr
->addr
.s_addr
!= 0 &&
941 (cache
= whine_malloc(sizeof(struct crec
))))
943 cache
->name
.namep
= nl
->name
;
944 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV4
| F_NAMEP
| F_CONFIG
;
945 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr
, INADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
948 if (!IN6_IS_ADDR_UNSPECIFIED(&hr
->addr6
) &&
949 (cache
= whine_malloc(sizeof(struct crec
))))
951 cache
->name
.namep
= nl
->name
;
952 cache
->flags
= F_HOSTS
| F_IMMORTAL
| F_FORWARD
| F_REVERSE
| F_IPV6
| F_NAMEP
| F_CONFIG
;
953 add_hosts_entry(cache
, (struct all_addr
*)&hr
->addr6
, IN6ADDRSZ
, 0, (struct crec
**)daemon
->packet
, revhashsz
);
958 if (option_bool(OPT_NO_HOSTS
) && !daemon
->addn_hosts
)
960 if (daemon
->cachesize
> 0)
961 my_syslog(LOG_INFO
, _("cleared cache"));
965 if (!option_bool(OPT_NO_HOSTS
))
966 total_size
= read_hostsfile(HOSTSFILE
, 0, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
968 daemon
->addn_hosts
= expand_filelist(daemon
->addn_hosts
);
969 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
970 if (!(ah
->flags
& AH_INACTIVE
))
971 total_size
= read_hostsfile(ah
->fname
, ah
->index
, total_size
, (struct crec
**)daemon
->packet
, revhashsz
);
975 struct in_addr
a_record_from_hosts(char *name
, time_t now
)
977 struct crec
*crecp
= NULL
;
980 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
981 if (crecp
->flags
& F_HOSTS
)
982 return *(struct in_addr
*)&crecp
->addr
;
984 my_syslog(MS_DHCP
| LOG_WARNING
, _("No IPv4 address found for %s"), name
);
990 void cache_unhash_dhcp(void)
992 struct crec
*cache
, **up
;
995 for (i
=0; i
<hash_size
; i
++)
996 for (cache
= hash_table
[i
], up
= &hash_table
[i
]; cache
; cache
= cache
->hash_next
)
997 if (cache
->flags
& F_DHCP
)
999 *up
= cache
->hash_next
;
1000 cache
->next
= dhcp_spare
;
1004 up
= &cache
->hash_next
;
1007 static void add_dhcp_cname(struct crec
*target
, time_t ttd
)
1009 struct crec
*aliasc
;
1012 for (a
= daemon
->cnames
; a
; a
= a
->next
)
1013 if (hostname_isequal(cache_get_name(target
), a
->target
))
1015 if ((aliasc
= dhcp_spare
))
1016 dhcp_spare
= dhcp_spare
->next
;
1017 else /* need new one */
1018 aliasc
= whine_malloc(sizeof(struct crec
));
1022 aliasc
->flags
= F_FORWARD
| F_NAMEP
| F_DHCP
| F_CNAME
;
1024 aliasc
->flags
|= F_IMMORTAL
;
1027 aliasc
->name
.namep
= a
->alias
;
1028 aliasc
->addr
.cname
.cache
= target
;
1029 aliasc
->addr
.cname
.uid
= target
->uid
;
1031 add_dhcp_cname(aliasc
, ttd
);
1036 void cache_add_dhcp_entry(char *host_name
, int prot
,
1037 struct all_addr
*host_address
, time_t ttd
)
1039 struct crec
*crec
= NULL
, *fail_crec
= NULL
;
1040 unsigned short flags
= F_IPV4
;
1042 size_t addrlen
= sizeof(struct in_addr
);
1045 if (prot
== AF_INET6
)
1048 addrlen
= sizeof(struct in6_addr
);
1052 inet_ntop(prot
, host_address
, daemon
->addrbuff
, ADDRSTRLEN
);
1054 while ((crec
= cache_find_by_name(crec
, host_name
, 0, flags
| F_CNAME
)))
1056 /* check all addresses associated with name */
1057 if (crec
->flags
& F_HOSTS
)
1059 if (crec
->flags
& F_CNAME
)
1060 my_syslog(MS_DHCP
| LOG_WARNING
,
1061 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1062 host_name
, daemon
->addrbuff
);
1063 else if (memcmp(&crec
->addr
.addr
, host_address
, addrlen
) == 0)
1068 else if (!(crec
->flags
& F_DHCP
))
1070 cache_scan_free(host_name
, NULL
, 0, crec
->flags
& (flags
| F_CNAME
| F_FORWARD
));
1071 /* scan_free deletes all addresses associated with name */
1076 /* if in hosts, don't need DHCP record */
1080 /* Name in hosts, address doesn't match */
1083 inet_ntop(prot
, &fail_crec
->addr
.addr
, daemon
->namebuff
, MAXDNAME
);
1084 my_syslog(MS_DHCP
| LOG_WARNING
,
1085 _("not giving name %s to the DHCP lease of %s because "
1086 "the name exists in %s with address %s"),
1087 host_name
, daemon
->addrbuff
,
1088 record_source(fail_crec
->uid
), daemon
->namebuff
);
1092 if ((crec
= cache_find_by_addr(NULL
, (struct all_addr
*)host_address
, 0, flags
)))
1094 if (crec
->flags
& F_NEG
)
1097 cache_scan_free(NULL
, (struct all_addr
*)host_address
, 0, flags
);
1103 if ((crec
= dhcp_spare
))
1104 dhcp_spare
= dhcp_spare
->next
;
1105 else /* need new one */
1106 crec
= whine_malloc(sizeof(struct crec
));
1108 if (crec
) /* malloc may fail */
1110 crec
->flags
= flags
| F_NAMEP
| F_DHCP
| F_FORWARD
;
1112 crec
->flags
|= F_IMMORTAL
;
1115 crec
->addr
.addr
= *host_address
;
1116 crec
->name
.namep
= host_name
;
1120 add_dhcp_cname(crec
, ttd
);
1126 void dump_cache(time_t now
)
1128 struct server
*serv
, *serv1
;
1130 my_syslog(LOG_INFO
, _("time %lu"), (unsigned long)now
);
1131 my_syslog(LOG_INFO
, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1132 daemon
->cachesize
, cache_live_freed
, cache_inserted
);
1133 my_syslog(LOG_INFO
, _("queries forwarded %u, queries answered locally %u"),
1134 daemon
->queries_forwarded
, daemon
->local_answer
);
1136 /* sum counts from different records for same server */
1137 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1138 serv
->flags
&= ~SERV_COUNTED
;
1140 for (serv
= daemon
->servers
; serv
; serv
= serv
->next
)
1142 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)))
1145 unsigned int queries
= 0, failed_queries
= 0;
1146 for (serv1
= serv
; serv1
; serv1
= serv1
->next
)
1147 if (!(serv1
->flags
&
1148 (SERV_NO_ADDR
| SERV_LITERAL_ADDRESS
| SERV_COUNTED
| SERV_USE_RESOLV
| SERV_NO_REBIND
)) &&
1149 sockaddr_isequal(&serv
->addr
, &serv1
->addr
))
1151 serv1
->flags
|= SERV_COUNTED
;
1152 queries
+= serv1
->queries
;
1153 failed_queries
+= serv1
->failed_queries
;
1155 port
= prettyprint_addr(&serv
->addr
, daemon
->addrbuff
);
1156 my_syslog(LOG_INFO
, _("server %s#%d: queries sent %u, retried or failed %u"), daemon
->addrbuff
, port
, queries
, failed_queries
);
1159 if (option_bool(OPT_DEBUG
) || option_bool(OPT_LOG
))
1161 struct crec
*cache
;
1163 my_syslog(LOG_INFO
, "Host Address Flags Expires");
1165 for (i
=0; i
<hash_size
; i
++)
1166 for (cache
= hash_table
[i
]; cache
; cache
= cache
->hash_next
)
1168 char *a
, *p
= daemon
->namebuff
;
1169 p
+= sprintf(p
, "%-40.40s ", cache_get_name(cache
));
1170 if ((cache
->flags
& F_NEG
) && (cache
->flags
& F_FORWARD
))
1172 else if (cache
->flags
& F_CNAME
)
1175 if (!is_outdated_cname_pointer(cache
))
1176 a
= cache_get_name(cache
->addr
.cname
.cache
);
1179 else if (cache
->flags
& F_DNSKEY
)
1181 a
= daemon
->addrbuff
;
1182 sprintf(a
, "%3u %u", cache
->addr
.key
.algo
, cache
->uid
);
1184 else if (cache
->flags
& F_DS
)
1186 a
= daemon
->addrbuff
;
1187 sprintf(a
, "%5u %3u %3u %u", cache
->addr
.key
.keytag
,
1188 cache
->addr
.key
.algo
, cache
->addr
.key
.digest
, cache
->uid
);
1193 a
= daemon
->addrbuff
;
1194 if (cache
->flags
& F_IPV4
)
1195 inet_ntop(AF_INET
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1197 else if (cache
->flags
& F_IPV6
)
1198 inet_ntop(AF_INET6
, &cache
->addr
.addr
, a
, ADDRSTRLEN
);
1202 p
+= sprintf(p
, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a
,
1203 cache
->flags
& F_IPV4
? "4" : "",
1204 cache
->flags
& F_IPV6
? "6" : "",
1205 cache
->flags
& F_DNSKEY
? "K" : "",
1206 cache
->flags
& F_DS
? "S" : "",
1207 cache
->flags
& F_CNAME
? "C" : "",
1208 cache
->flags
& F_FORWARD
? "F" : " ",
1209 cache
->flags
& F_REVERSE
? "R" : " ",
1210 cache
->flags
& F_IMMORTAL
? "I" : " ",
1211 cache
->flags
& F_DHCP
? "D" : " ",
1212 cache
->flags
& F_NEG
? "N" : " ",
1213 cache
->flags
& F_NXDOMAIN
? "X" : " ",
1214 cache
->flags
& F_HOSTS
? "H" : " ",
1215 cache
->flags
& F_DNSSECOK
? "V" : " ");
1216 #ifdef HAVE_BROKEN_RTC
1217 p
+= sprintf(p
, "%lu", cache
->flags
& F_IMMORTAL
? 0: (unsigned long)(cache
->ttd
- now
));
1219 p
+= sprintf(p
, "%s", cache
->flags
& F_IMMORTAL
? "\n" : ctime(&(cache
->ttd
)));
1220 /* ctime includes trailing \n - eat it */
1223 my_syslog(LOG_INFO
, daemon
->namebuff
);
1228 char *record_source(int index
)
1230 struct hostsfile
*ah
;
1235 for (ah
= daemon
->addn_hosts
; ah
; ah
= ah
->next
)
1236 if (ah
->index
== index
)
1242 void querystr(char *desc
, char *str
, unsigned short type
)
1246 sprintf(str
, "%s[type=%d]", desc
, type
);
1247 for (i
= 0; i
< (sizeof(typestr
)/sizeof(typestr
[0])); i
++)
1248 if (typestr
[i
].type
== type
)
1249 sprintf(str
,"%s[%s]", desc
, typestr
[i
].name
);
1252 void log_query(unsigned int flags
, char *name
, struct all_addr
*addr
, char *arg
)
1254 char *source
, *dest
= daemon
->addrbuff
;
1257 if (!option_bool(OPT_LOG
))
1263 inet_ntop(flags
& F_IPV4
? AF_INET
: AF_INET6
,
1264 addr
, daemon
->addrbuff
, ADDRSTRLEN
);
1266 strncpy(daemon
->addrbuff
, inet_ntoa(addr
->addr
.addr4
), ADDRSTRLEN
);
1270 if (flags
& F_REVERSE
)
1273 name
= daemon
->addrbuff
;
1278 if (flags
& F_NXDOMAIN
)
1281 dest
= "NXDOMAIN-IPv4";
1282 else if (flags
& F_IPV6
)
1283 dest
= "NXDOMAIN-IPv6";
1290 dest
= "NODATA-IPv4";
1291 else if (flags
& F_IPV6
)
1292 dest
= "NODATA-IPv6";
1297 else if (flags
& F_CNAME
)
1299 else if (flags
& F_RRNAME
)
1302 if (flags
& F_CONFIG
)
1304 else if (flags
& F_DHCP
)
1306 else if (flags
& F_HOSTS
)
1308 else if (flags
& F_UPSTREAM
)
1310 else if (flags
& F_AUTH
)
1312 else if (flags
& F_SERVER
)
1314 source
= "forwarded";
1317 else if (flags
& F_QUERY
)
1325 if (strlen(name
) == 0)
1328 my_syslog(LOG_INFO
, "%s %s %s %s", source
, name
, verb
, dest
);
1332 struct keydata
*keydata_alloc(char *data
, size_t len
)
1334 struct keydata
*block
, *ret
= NULL
;
1335 struct keydata
**prev
= &ret
;
1342 block
= keyblock_free
;
1343 keyblock_free
= block
->next
;
1346 block
= whine_malloc(sizeof(struct keydata
));
1350 /* failed to alloc, free partial chain */
1355 blen
= len
> KEYBLOCK_LEN
? KEYBLOCK_LEN
: len
;
1356 memcpy(block
->key
, data
, blen
);
1360 prev
= &block
->next
;
1367 void keydata_free(struct keydata
*blocks
)
1369 struct keydata
*tmp
;
1373 for (tmp
= blocks
; tmp
->next
; tmp
= tmp
->next
);
1374 tmp
->next
= keyblock_free
;
1375 keyblock_free
= blocks
;