blob: 6fdeba26f3abd446933d4adb314325cdf16cb9e1 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley5aabfc72007-08-29 11:24:47 +010019static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +010020#ifdef HAVE_DHCP
21static struct crec *dhcp_spare = NULL;
22#endif
23static struct crec *new_chain = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static int cache_inserted = 0, cache_live_freed = 0, insert_error;
25static union bigname *big_free = NULL;
26static int bignames_left, hash_size;
27static int uid = 0;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +010028#ifdef HAVE_DNSSEC
29static struct keydata *keyblock_free = NULL;
30#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031
Simon Kelley16972692006-10-16 20:04:18 +010032/* type->string mapping: this is also used by the name-hash function as a mixing table. */
33static const struct {
34 unsigned int type;
35 const char * const name;
36} typestr[] = {
37 { 1, "A" },
38 { 2, "NS" },
39 { 5, "CNAME" },
40 { 6, "SOA" },
41 { 10, "NULL" },
42 { 11, "WKS" },
43 { 12, "PTR" },
44 { 13, "HINFO" },
45 { 15, "MX" },
46 { 16, "TXT" },
47 { 22, "NSAP" },
48 { 23, "NSAP_PTR" },
49 { 24, "SIG" },
50 { 25, "KEY" },
51 { 28, "AAAA" },
52 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010053 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010054 { 36, "KX" },
55 { 37, "CERT" },
56 { 38, "A6" },
57 { 39, "DNAME" },
58 { 41, "OPT" },
Simon Kelley832af0b2007-01-21 20:01:28 +000059 { 48, "DNSKEY" },
60 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010061 { 250, "TSIG" },
62 { 251, "IXFR" },
63 { 252, "AXFR" },
64 { 253, "MAILB" },
65 { 254, "MAILA" },
66 { 255, "ANY" }
67};
68
Simon Kelley9e4abcb2004-01-22 19:47:41 +000069static void cache_free(struct crec *crecp);
70static void cache_unlink(struct crec *crecp);
71static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010072static void rehash(int size);
73static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074
Simon Kelley5aabfc72007-08-29 11:24:47 +010075void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000076{
77 struct crec *crecp;
78 int i;
79
Simon Kelley5aabfc72007-08-29 11:24:47 +010080 bignames_left = daemon->cachesize/10;
81
82 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000083 {
Simon Kelley5aabfc72007-08-29 11:24:47 +010084 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +000085
Simon Kelley5aabfc72007-08-29 11:24:47 +010086 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000087 {
88 cache_link(crecp);
89 crecp->flags = 0;
Simon Kelley26128d22004-11-14 16:43:54 +000090 crecp->uid = uid++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000091 }
92 }
93
Simon Kelley4011c4e2006-10-28 16:26:19 +010094 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +010095 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000096}
97
Simon Kelley4011c4e2006-10-28 16:26:19 +010098/* 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
101 expand the table. */
102static void rehash(int size)
103{
104 struct crec **new, **old, *p, *tmp;
105 int i, new_size, old_size;
106
107 /* hash_size is a power of two. */
108 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
109
110 /* must succeed in getting first instance, failure later is non-fatal */
111 if (!hash_table)
112 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100113 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100114 return;
115
116 for(i = 0; i < new_size; i++)
117 new[i] = NULL;
118
119 old = hash_table;
120 old_size = hash_size;
121 hash_table = new;
122 hash_size = new_size;
123
124 if (old)
125 {
126 for (i = 0; i < old_size; i++)
127 for (p = old[i]; p ; p = tmp)
128 {
129 tmp = p->hash_next;
130 cache_hash(p);
131 }
132 free(old);
133 }
134}
135
Simon Kelley3d8df262005-08-29 12:19:27 +0100136static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000137{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100138 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100139 const unsigned char *mix_tab = (const unsigned char*)typestr;
140
Simon Kelley3d8df262005-08-29 12:19:27 +0100141 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100142 {
143 /* don't use tolower and friends here - they may be messed up by LOCALE */
144 if (c >= 'A' && c <= 'Z')
145 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100146 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100147 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000148
149 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100150 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000151}
152
153static void cache_hash(struct crec *crecp)
154{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000155 /* 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 */
159
160 struct crec **up = hash_bucket(cache_get_name(crecp));
161
162 if (!(crecp->flags & F_REVERSE))
163 {
164 while (*up && ((*up)->flags & F_REVERSE))
165 up = &((*up)->hash_next);
166
167 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000168 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000169 up = &((*up)->hash_next);
170 }
171 crecp->hash_next = *up;
172 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173}
174
175static void cache_free(struct crec *crecp)
176{
177 crecp->flags &= ~F_FORWARD;
178 crecp->flags &= ~F_REVERSE;
Simon Kelley26128d22004-11-14 16:43:54 +0000179 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100180
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000181 if (cache_tail)
182 cache_tail->next = crecp;
183 else
184 cache_head = crecp;
185 crecp->prev = cache_tail;
186 crecp->next = NULL;
187 cache_tail = crecp;
188
189 /* retrieve big name for further use. */
190 if (crecp->flags & F_BIGNAME)
191 {
192 crecp->name.bname->next = big_free;
193 big_free = crecp->name.bname;
194 crecp->flags &= ~F_BIGNAME;
195 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100196#ifdef HAVE_DNSSEC
197 else if (crecp->flags & (F_DNSKEY | F_DS))
198 keydata_free(crecp->addr.key.keydata);
199#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000200}
201
202/* insert a new cache entry at the head of the list (youngest entry) */
203static void cache_link(struct crec *crecp)
204{
205 if (cache_head) /* check needed for init code */
206 cache_head->prev = crecp;
207 crecp->next = cache_head;
208 crecp->prev = NULL;
209 cache_head = crecp;
210 if (!cache_tail)
211 cache_tail = crecp;
212}
213
214/* remove an arbitrary cache entry for promotion */
215static void cache_unlink (struct crec *crecp)
216{
217 if (crecp->prev)
218 crecp->prev->next = crecp->next;
219 else
220 cache_head = crecp->next;
221
222 if (crecp->next)
223 crecp->next->prev = crecp->prev;
224 else
225 cache_tail = crecp->prev;
226}
227
228char *cache_get_name(struct crec *crecp)
229{
230 if (crecp->flags & F_BIGNAME)
231 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000232 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000233 return crecp->name.namep;
234
235 return crecp->name.sname;
236}
237
Simon Kelleyb75e9362012-12-07 11:50:41 +0000238struct crec *cache_enumerate(int init)
239{
240 static int bucket;
241 static struct crec *cache;
242
243 if (init)
244 {
245 bucket = 0;
246 cache = NULL;
247 }
248 else if (cache && cache->hash_next)
249 cache = cache->hash_next;
250 else
251 {
252 cache = NULL;
253 while (bucket < hash_size)
254 if ((cache = hash_table[bucket++]))
255 break;
256 }
257
258 return cache;
259}
260
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100261static int is_outdated_cname_pointer(struct crec *crecp)
262{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100263 if (!(crecp->flags & F_CNAME))
264 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100265
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100266 /* NB. record may be reused as DS or DNSKEY, where uid is
267 overloaded for something completely different */
268 if (crecp->addr.cname.cache &&
Simon Kelley611ebc52012-07-16 16:23:46 +0100269 (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100270 crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100271 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100272
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100273 return 1;
274}
275
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000276static int is_expired(time_t now, struct crec *crecp)
277{
278 if (crecp->flags & F_IMMORTAL)
279 return 0;
280
281 if (difftime(now, crecp->ttd) < 0)
282 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100283
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000284 return 1;
285}
286
287static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000288{
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.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000294 If (flags == 0) remove any expired entries in the whole cache.
295
296 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000297 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000298
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000299 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. */
301
302 struct crec *crecp, **up;
303
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000304 if (flags & F_FORWARD)
305 {
Simon Kelley6b010842007-02-12 20:32:07 +0000306 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000307 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
308 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000309 *up = crecp->hash_next;
310 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000311 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000312 cache_unlink(crecp);
313 cache_free(crecp);
314 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000315 }
316 else if ((crecp->flags & F_FORWARD) &&
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100317 ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000318 hostname_isequal(cache_get_name(crecp), name))
319 {
320 if (crecp->flags & (F_HOSTS | F_DHCP))
321 return 0;
322 *up = crecp->hash_next;
323 cache_unlink(crecp);
324 cache_free(crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000325 }
326 else
327 up = &crecp->hash_next;
328 }
329 else
330 {
331 int i;
332#ifdef HAVE_IPV6
333 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
334#else
335 int addrlen = INADDRSZ;
336#endif
337 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000338 for (crecp = hash_table[i], up = &hash_table[i];
339 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
340 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000341 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342 {
343 *up = crecp->hash_next;
344 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
345 {
346 cache_unlink(crecp);
347 cache_free(crecp);
348 }
349 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000350 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)
354 {
355 *up = crecp->hash_next;
356 cache_unlink(crecp);
357 cache_free(crecp);
358 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 else
360 up = &crecp->hash_next;
361 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000362
363 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000364}
365
366/* Note: The normal calling sequence is
367 cache_start_insert
368 cache_insert * n
369 cache_end_insert
370
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. */
373
374void cache_start_insert(void)
375{
376 /* Free any entries which didn't get committed during the last
377 insert due to error.
378 */
379 while (new_chain)
380 {
381 struct crec *tmp = new_chain->next;
382 cache_free(new_chain);
383 new_chain = tmp;
384 }
385 new_chain = NULL;
386 insert_error = 0;
387}
388
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100389struct crec *cache_insert(char *name, struct all_addr *addr,
390 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000391{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000392 struct crec *new;
393 union bigname *big_name = NULL;
394 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100395 int free_avail = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000396
Simon Kelley1d6c6392012-12-14 11:19:36 +0000397 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
Simon Kelley1d860412012-09-20 20:48:04 +0100398 ttl = daemon->max_cache_ttl;
399
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100400 /* Don't log keys */
401 if (flags & (F_IPV4 | F_IPV6))
402 log_query(flags | F_UPSTREAM, name, addr, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000403
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000404 /* if previous insertion failed give up now. */
405 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100406 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000407
408 /* First remove any expired entries and entries for the name/address we
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000409 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))
412 {
413 insert_error = 1;
414 return NULL;
415 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000416
417 /* Now get a cache entry from the end of the LRU list */
418 while (1) {
419 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
420 {
421 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100422 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000423 }
424
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. */
428
429 if (new->flags & (F_FORWARD | F_REVERSE))
430 {
Simon Kelley9e038942008-05-30 20:06:34 +0100431 /* If free_avail set, we believe that an entry has been freed.
432 Bugs have been known to make this not true, resulting in
Simon Kelley1a6bca82008-07-11 11:11:42 +0100433 a tight loop here. If that happens, abandon the
Simon Kelley9e038942008-05-30 20:06:34 +0100434 insert. Once in this state, all inserts will probably fail. */
Simon Kelley9e038942008-05-30 20:06:34 +0100435 if (free_avail)
436 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100437 insert_error = 1;
Simon Kelley9e038942008-05-30 20:06:34 +0100438 return NULL;
439 }
440
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 if (freed_all)
442 {
Simon Kelley9e038942008-05-30 20:06:34 +0100443 free_avail = 1; /* Must be free space now. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100444 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445 cache_live_freed++;
446 }
447 else
448 {
449 cache_scan_free(NULL, NULL, now, 0);
450 freed_all = 1;
451 }
452 continue;
453 }
454
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))
458 {
459 if (big_free)
460 {
461 big_name = big_free;
462 big_free = big_free->next;
463 }
464 else if (!bignames_left ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100465 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000466 {
467 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100468 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000469 }
470 else
471 bignames_left--;
472
473 }
474
475 /* Got the rest: finally grab entry. */
476 cache_unlink(new);
477 break;
478 }
479
480 new->flags = flags;
481 if (big_name)
482 {
483 new->name.bname = big_name;
484 new->flags |= F_BIGNAME;
485 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100486
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487 if (name)
488 strcpy(cache_get_name(new), name);
489 else
490 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100491
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000492 if (addr)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100493 new->addr.addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100494
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000495 new->ttd = now + (time_t)ttl;
496 new->next = new_chain;
497 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100498
499 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000500}
501
502/* after end of insertion, commit the new entries */
503void cache_end_insert(void)
504{
505 if (insert_error)
506 return;
507
508 while (new_chain)
509 {
510 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100511 /* drop CNAMEs which didn't find a target. */
512 if (is_outdated_cname_pointer(new_chain))
513 cache_free(new_chain);
514 else
515 {
516 cache_hash(new_chain);
517 cache_link(new_chain);
518 cache_inserted++;
519 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000520 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000521 }
522 new_chain = NULL;
523}
524
525struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
526{
527 struct crec *ans;
528
529 if (crecp) /* iterating */
530 ans = crecp->next;
531 else
532 {
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;
Simon Kelley28866e92011-02-14 20:19:14 +0000536 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000537
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000538 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
539 {
540 next = crecp->hash_next;
541
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000542 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000543 {
544 if ((crecp->flags & F_FORWARD) &&
545 (crecp->flags & prot) &&
546 hostname_isequal(cache_get_name(crecp), name))
547 {
548 if (crecp->flags & (F_HOSTS | F_DHCP))
549 {
550 *chainp = crecp;
551 chainp = &crecp->next;
552 }
553 else
554 {
555 cache_unlink(crecp);
556 cache_link(crecp);
557 }
558
Simon Kelley824af852008-02-12 20:43:05 +0000559 /* 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
562 order invariants.
563 */
Simon Kelley9e038942008-05-30 20:06:34 +0100564 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000565 {
566 *up = crecp->hash_next;
567 crecp->hash_next = *insert;
568 *insert = crecp;
569 insert = &crecp->hash_next;
570 }
Simon Kelley9e038942008-05-30 20:06:34 +0100571 else
572 {
573 if (!insert)
574 {
575 insert = up;
576 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
577 }
578 up = &crecp->hash_next;
579 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000580 }
581 else
582 /* case : not expired, incorrect entry. */
583 up = &crecp->hash_next;
584 }
585 else
586 {
587 /* expired entry, free it */
588 *up = crecp->hash_next;
589 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
590 {
591 cache_unlink(crecp);
592 cache_free(crecp);
593 }
594 }
595 }
596
597 *chainp = cache_head;
598 }
599
600 if (ans &&
601 (ans->flags & F_FORWARD) &&
602 (ans->flags & prot) &&
603 hostname_isequal(cache_get_name(ans), name))
604 return ans;
605
606 return NULL;
607}
608
609struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
610 time_t now, unsigned short prot)
611{
612 struct crec *ans;
613#ifdef HAVE_IPV6
614 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
615#else
616 int addrlen = INADDRSZ;
617#endif
618
619 if (crecp) /* iterating */
620 ans = crecp->next;
621 else
622 {
623 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000624 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
626 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000627 int i;
628 struct crec **up, **chainp = &ans;
629
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000630 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)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000634 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000635 {
Simon Kelley6b010842007-02-12 20:32:07 +0000636 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100637 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000638 {
639 if (crecp->flags & (F_HOSTS | F_DHCP))
640 {
641 *chainp = crecp;
642 chainp = &crecp->next;
643 }
644 else
645 {
646 cache_unlink(crecp);
647 cache_link(crecp);
648 }
649 }
650 up = &crecp->hash_next;
651 }
652 else
653 {
654 *up = crecp->hash_next;
655 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
656 {
657 cache_unlink(crecp);
658 cache_free(crecp);
659 }
660 }
661
662 *chainp = cache_head;
663 }
664
665 if (ans &&
666 (ans->flags & F_REVERSE) &&
667 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100668 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000669 return ans;
670
671 return NULL;
672}
673
Simon Kelley611ebc52012-07-16 16:23:46 +0100674static void add_hosts_cname(struct crec *target)
675{
676 struct crec *crec;
677 struct cname *a;
678
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))))
682 {
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;
687 cache_hash(crec);
688 add_hosts_cname(crec); /* handle chains */
689 }
690}
691
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100692static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelleye759d422012-03-16 13:18:57 +0000693 int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000694{
Simon Kelleye759d422012-03-16 13:18:57 +0000695 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
Simon Kelley9009d742008-11-14 20:04:27 +0000696 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000697 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000698
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000699 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000700 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000701 {
Simon Kelley9009d742008-11-14 20:04:27 +0000702 nameexists = 1;
703 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
704 {
705 free(cache);
706 return;
707 }
708 }
709
710 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000711 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
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000713 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.
Simon Kelley205fafa2012-01-11 21:31:51 +0000716
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000717 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000718
719 This complexity avoids O(n^2) divergent CPU use whilst reading
720 large (10000 entry) hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000721
Simon Kelley205fafa2012-01-11 21:31:51 +0000722 /* hash address */
723 for (j = 0, i = 0; i < addrlen; i++)
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000724 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
Simon Kelley915363f2012-01-11 22:00:48 +0000725
726 for (lookup = rhash[j]; lookup; lookup = lookup->next)
Simon Kelleye759d422012-03-16 13:18:57 +0000727 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelley205fafa2012-01-11 21:31:51 +0000728 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
Simon Kelley9009d742008-11-14 20:04:27 +0000729 {
Simon Kelleye759d422012-03-16 13:18:57 +0000730 cache->flags &= ~F_REVERSE;
Simon Kelley205fafa2012-01-11 21:31:51 +0000731 break;
Simon Kelley9009d742008-11-14 20:04:27 +0000732 }
733
Simon Kelley915363f2012-01-11 22:00:48 +0000734 /* maintain address hash chain, insert new unique address */
735 if (!lookup)
736 {
737 cache->next = rhash[j];
738 rhash[j] = cache;
739 }
740
Simon Kelley9009d742008-11-14 20:04:27 +0000741 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000742 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000743 cache_hash(cache);
744
745 /* don't need to do alias stuff for second and subsequent addresses. */
746 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100747 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000748}
749
750static int eatspace(FILE *f)
751{
752 int c, nl = 0;
753
754 while (1)
755 {
756 if ((c = getc(f)) == '#')
757 while (c != '\n' && c != EOF)
758 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000759
Simon Kelley9009d742008-11-14 20:04:27 +0000760 if (c == EOF)
761 return 1;
762
763 if (!isspace(c))
764 {
765 ungetc(c, f);
766 return nl;
767 }
768
769 if (c == '\n')
770 nl = 1;
771 }
772}
773
774static int gettok(FILE *f, char *token)
775{
776 int c, count = 0;
777
778 while (1)
779 {
780 if ((c = getc(f)) == EOF)
781 return (count == 0) ? EOF : 1;
782
783 if (isspace(c) || c == '#')
784 {
785 ungetc(c, f);
786 return eatspace(f);
787 }
788
789 if (count < (MAXDNAME - 1))
790 {
791 token[count++] = c;
792 token[count] = 0;
793 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000794 }
795}
796
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000797static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000798{
799 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000800 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100801 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000802 unsigned short flags = 0;
803 struct all_addr addr;
804 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100805
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000806 if (!f)
807 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100808 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
Simon Kelley4011c4e2006-10-28 16:26:19 +0100809 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000810 }
Simon Kelley9009d742008-11-14 20:04:27 +0000811
812 eatspace(f);
813
814 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000815 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000817
Simon Kelley3d8df262005-08-29 12:19:27 +0100818 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000819 {
820 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
821 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000822 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823 }
Simon Kelleye759d422012-03-16 13:18:57 +0000824#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100825 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000826 {
827 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
828 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000829 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000830 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000831#endif
832 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000833 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100834 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000835 while (atnl == 0)
836 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000837 continue;
838 }
Simon Kelley9009d742008-11-14 20:04:27 +0000839
Simon Kelley9009d742008-11-14 20:04:27 +0000840 addr_count++;
841
842 /* rehash every 1000 names. */
843 if ((name_count - cache_size) > 1000)
844 {
845 rehash(name_count);
846 cache_size = name_count;
847 }
848
849 while (atnl == 0)
850 {
851 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100852 int fqdn, nomem;
853 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000854
855 if ((atnl = gettok(f, token)) == EOF)
856 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000857
Simon Kelley9009d742008-11-14 20:04:27 +0000858 fqdn = !!strchr(token, '.');
859
Simon Kelley1f15b812009-10-13 17:49:32 +0100860 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000861 {
862 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000863 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000864 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100865 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000866 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100867 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000868 strcat(cache->name.sname, ".");
869 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000870 cache->flags = flags;
871 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000872 name_count++;
873 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100874 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000875 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100876 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000877 cache->flags = flags;
878 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000879 name_count++;
880 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100881 free(canon);
882
Simon Kelley9009d742008-11-14 20:04:27 +0000883 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100884 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +0000885 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
886 }
887 }
888
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000889 fclose(f);
Simon Kelley4011c4e2006-10-28 16:26:19 +0100890 rehash(name_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000891
Simon Kelleyf2621c72007-04-29 19:47:21 +0100892 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000893
Simon Kelley4011c4e2006-10-28 16:26:19 +0100894 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000895}
896
Simon Kelley7622fc02009-06-04 20:32:05 +0100897void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898{
899 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000900 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +0100901 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +0000902 struct host_record *hr;
903 struct name_list *nl;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904
Simon Kelley59353a62004-11-21 19:34:28 +0000905 cache_inserted = cache_live_freed = 0;
906
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000907 for (i=0; i<hash_size; i++)
908 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
909 {
910 tmp = cache->hash_next;
911 if (cache->flags & F_HOSTS)
912 {
913 *up = cache->hash_next;
914 free(cache);
915 }
916 else if (!(cache->flags & F_DHCP))
917 {
918 *up = cache->hash_next;
919 if (cache->flags & F_BIGNAME)
920 {
921 cache->name.bname->next = big_free;
922 big_free = cache->name.bname;
923 }
924 cache->flags = 0;
925 }
926 else
927 up = &cache->hash_next;
928 }
929
Simon Kelleye759d422012-03-16 13:18:57 +0000930 /* 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;
935
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)
939 {
940 if (hr->addr.s_addr != 0 &&
941 (cache = whine_malloc(sizeof(struct crec))))
942 {
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);
946 }
947#ifdef HAVE_IPV6
948 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
949 (cache = whine_malloc(sizeof(struct crec))))
950 {
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);
954 }
955#endif
956 }
957
Simon Kelley28866e92011-02-14 20:19:14 +0000958 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000959 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100960 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100961 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000962 return;
963 }
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000964
Simon Kelley28866e92011-02-14 20:19:14 +0000965 if (!option_bool(OPT_NO_HOSTS))
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000966 total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley28866e92011-02-14 20:19:14 +0000967
968 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
Simon Kelley7622fc02009-06-04 20:32:05 +0100969 for (ah = daemon->addn_hosts; ah; ah = ah->next)
970 if (!(ah->flags & AH_INACTIVE))
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000971 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000972}
973
Simon Kelley7622fc02009-06-04 20:32:05 +0100974#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +0100975struct in_addr a_record_from_hosts(char *name, time_t now)
976{
977 struct crec *crecp = NULL;
978 struct in_addr ret;
979
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;
983
984 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
985
986 ret.s_addr = 0;
987 return ret;
988}
989
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000990void cache_unhash_dhcp(void)
991{
Simon Kelley6b010842007-02-12 20:32:07 +0000992 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000993 int i;
994
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)
Simon Kelley6b010842007-02-12 20:32:07 +0000998 {
999 *up = cache->hash_next;
1000 cache->next = dhcp_spare;
1001 dhcp_spare = cache;
1002 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001003 else
1004 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001005}
1006
Simon Kelley611ebc52012-07-16 16:23:46 +01001007static void add_dhcp_cname(struct crec *target, time_t ttd)
1008{
1009 struct crec *aliasc;
1010 struct cname *a;
1011
1012 for (a = daemon->cnames; a; a = a->next)
1013 if (hostname_isequal(cache_get_name(target), a->target))
1014 {
1015 if ((aliasc = dhcp_spare))
1016 dhcp_spare = dhcp_spare->next;
1017 else /* need new one */
1018 aliasc = whine_malloc(sizeof(struct crec));
1019
1020 if (aliasc)
1021 {
1022 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
1023 if (ttd == 0)
1024 aliasc->flags |= F_IMMORTAL;
1025 else
1026 aliasc->ttd = ttd;
1027 aliasc->name.namep = a->alias;
1028 aliasc->addr.cname.cache = target;
1029 aliasc->addr.cname.uid = target->uid;
1030 cache_hash(aliasc);
1031 add_dhcp_cname(aliasc, ttd);
1032 }
1033 }
1034}
1035
Simon Kelley4cb1b322012-02-06 14:30:41 +00001036void cache_add_dhcp_entry(char *host_name, int prot,
1037 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001038{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001039 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001040 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001041 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001042 size_t addrlen = sizeof(struct in_addr);
1043
1044#ifdef HAVE_IPV6
1045 if (prot == AF_INET6)
1046 {
1047 flags = F_IPV6;
1048 addrlen = sizeof(struct in6_addr);
1049 }
1050#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001051
Simon Kelley12d71ed2012-08-30 15:16:41 +01001052 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1053
Simon Kelley4cb1b322012-02-06 14:30:41 +00001054 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001055 {
Simon Kelley824af852008-02-12 20:43:05 +00001056 /* check all addresses associated with name */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001057 if (crec->flags & F_HOSTS)
Simon Kelley1ab84e22004-01-29 16:48:35 +00001058 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001059 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001060 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001061 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001062 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001063 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1064 in_hosts = 1;
1065 else
1066 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001067 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001068 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001069 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001070 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001071 /* scan_free deletes all addresses associated with name */
1072 break;
1073 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001074 }
Simon Kelley824af852008-02-12 20:43:05 +00001075
Simon Kelley12d71ed2012-08-30 15:16:41 +01001076 /* if in hosts, don't need DHCP record */
1077 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001078 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001079
1080 /* Name in hosts, address doesn't match */
1081 if (fail_crec)
1082 {
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);
1089 return;
1090 }
1091
1092 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1093 {
1094 if (crec->flags & F_NEG)
1095 {
1096 flags |= F_REVERSE;
1097 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1098 }
1099 }
1100 else
1101 flags |= F_REVERSE;
1102
1103 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001104 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001105 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001106 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001107
1108 if (crec) /* malloc may fail */
1109 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001110 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001111 if (ttd == 0)
1112 crec->flags |= F_IMMORTAL;
1113 else
1114 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001115 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001116 crec->name.namep = host_name;
Simon Kelley9009d742008-11-14 20:04:27 +00001117 crec->uid = uid++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001118 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001119
Simon Kelley611ebc52012-07-16 16:23:46 +01001120 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001121 }
1122}
Simon Kelley7622fc02009-06-04 20:32:05 +01001123#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001124
Simon Kelley9009d742008-11-14 20:04:27 +00001125
Simon Kelley5aabfc72007-08-29 11:24:47 +01001126void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001127{
Simon Kelley824af852008-02-12 20:43:05 +00001128 struct server *serv, *serv1;
1129
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);
1135
Simon Kelley824af852008-02-12 20:43:05 +00001136 /* sum counts from different records for same server */
1137 for (serv = daemon->servers; serv; serv = serv->next)
1138 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001139
Simon Kelley824af852008-02-12 20:43:05 +00001140 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001141 if (!(serv->flags &
1142 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001143 {
1144 int port;
1145 unsigned int queries = 0, failed_queries = 0;
1146 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001147 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))
Simon Kelley824af852008-02-12 20:43:05 +00001150 {
1151 serv1->flags |= SERV_COUNTED;
1152 queries += serv1->queries;
1153 failed_queries += serv1->failed_queries;
1154 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001155 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);
Simon Kelley824af852008-02-12 20:43:05 +00001157 }
1158
Simon Kelley28866e92011-02-14 20:19:14 +00001159 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001160 {
1161 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001162 int i;
Simon Kelley28866e92011-02-14 20:19:14 +00001163 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001164
1165 for (i=0; i<hash_size; i++)
1166 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1167 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001168 char *a, *p = daemon->namebuff;
1169 p += sprintf(p, "%-40.40s ", cache_get_name(cache));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001170 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001171 a = "";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001172 else if (cache->flags & F_CNAME)
1173 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001174 a = "";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001175 if (!is_outdated_cname_pointer(cache))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001176 a = cache_get_name(cache->addr.cname.cache);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001177 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001178#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001179 else if (cache->flags & F_DNSKEY)
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001180 {
1181 a = daemon->addrbuff;
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001182 sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);
1183 }
1184 else if (cache->flags & F_DS)
1185 {
1186 a = daemon->addrbuff;
1187 sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,
1188 cache->addr.key.algo, cache->addr.key.digest, cache->uid);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001189 }
1190#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001191 else
1192 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001193 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001194 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001195 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001196#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001197 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001198 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001199#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001200 }
1201
1202 p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001203 cache->flags & F_IPV4 ? "4" : "",
1204 cache->flags & F_IPV6 ? "6" : "",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001205 cache->flags & F_DNSKEY ? "K" : "",
1206 cache->flags & F_DS ? "S" : "",
Simon Kelleyf2621c72007-04-29 19:47:21 +01001207 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" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001214 cache->flags & F_HOSTS ? "H" : " ",
1215 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001216#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001217 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001218#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001219 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1220 /* ctime includes trailing \n - eat it */
1221 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001222#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001223 my_syslog(LOG_INFO, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001224 }
1225 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001226}
1227
Simon Kelley7622fc02009-06-04 20:32:05 +01001228char *record_source(int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001229{
Simon Kelley7622fc02009-06-04 20:32:05 +01001230 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001231
Simon Kelley7622fc02009-06-04 20:32:05 +01001232 if (index == 0)
1233 return HOSTSFILE;
1234
1235 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1236 if (ah->index == index)
1237 return ah->fname;
1238
1239 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001240}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001241
Simon Kelley4f7b3042012-11-28 21:27:02 +00001242void querystr(char *desc, char *str, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001243{
1244 unsigned int i;
1245
Simon Kelley4f7b3042012-11-28 21:27:02 +00001246 sprintf(str, "%s[type=%d]", desc, type);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001247 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1248 if (typestr[i].type == type)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001249 sprintf(str,"%s[%s]", desc, typestr[i].name);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001250}
1251
Simon Kelley28866e92011-02-14 20:19:14 +00001252void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001253{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001254 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001255 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001256
Simon Kelley28866e92011-02-14 20:19:14 +00001257 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001258 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001259
1260 if (addr)
1261 {
1262#ifdef HAVE_IPV6
1263 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
Simon Kelleyc72daea2012-01-05 21:33:27 +00001264 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001265#else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001266 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001267#endif
1268 }
1269
1270 if (flags & F_REVERSE)
1271 {
1272 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001273 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001274 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001275
1276 if (flags & F_NEG)
1277 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001278 if (flags & F_NXDOMAIN)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001279 {
1280 if (flags & F_IPV4)
1281 dest = "NXDOMAIN-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001282 else if (flags & F_IPV6)
1283 dest = "NXDOMAIN-IPv6";
1284 else
1285 dest = "NXDOMAIN";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001286 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001287 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001288 {
1289 if (flags & F_IPV4)
1290 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001291 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001292 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001293 else
1294 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001295 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001296 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001297 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001298 dest = "<CNAME>";
1299 else if (flags & F_RRNAME)
1300 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001301
Simon Kelley1f15b812009-10-13 17:49:32 +01001302 if (flags & F_CONFIG)
1303 source = "config";
1304 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001305 source = "DHCP";
1306 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001307 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001308 else if (flags & F_UPSTREAM)
1309 source = "reply";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001310 else if (flags & F_AUTH)
1311 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001312 else if (flags & F_SERVER)
1313 {
1314 source = "forwarded";
1315 verb = "to";
1316 }
1317 else if (flags & F_QUERY)
1318 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001319 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001320 verb = "from";
1321 }
1322 else
1323 source = "cached";
1324
Simon Kelley3d8df262005-08-29 12:19:27 +01001325 if (strlen(name) == 0)
1326 name = ".";
1327
Simon Kelley28866e92011-02-14 20:19:14 +00001328 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001329}
1330
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001331#ifdef HAVE_DNSSEC
1332struct keydata *keydata_alloc(char *data, size_t len)
1333{
1334 struct keydata *block, *ret = NULL;
1335 struct keydata **prev = &ret;
1336 while (len > 0)
1337 {
1338 if (keyblock_free)
1339 {
1340 block = keyblock_free;
1341 keyblock_free = block->next;
1342 }
1343 else
1344 block = whine_malloc(sizeof(struct keydata));
1345
1346 if (!block)
1347 {
1348 /* failed to alloc, free partial chain */
1349 keydata_free(ret);
1350 return NULL;
1351 }
1352
1353 memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len);
1354 data += KEYBLOCK_LEN;
1355 len -= KEYBLOCK_LEN;
1356 *prev = block;
1357 prev = &block->next;
1358 block->next = NULL;
1359 }
1360
1361 return ret;
1362}
1363
1364void keydata_free(struct keydata *blocks)
1365{
1366 struct keydata *tmp;
1367
1368 if (blocks)
1369 {
1370 for (tmp = blocks; tmp->next; tmp = tmp->next);
1371 tmp->next = keyblock_free;
1372 keyblock_free = blocks;
1373 }
1374}
1375#endif
1376
1377