blob: ddbc5c0b145f791a0e4bcc1f3699c152974f1bd3 [file] [log] [blame]
Simon Kelley59546082012-01-06 20:02:04 +00001/* dnsmasq is Copyright (c) 2000-2012 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 Kelleyfd9fa482004-10-21 20:24:00 +0100238static int is_outdated_cname_pointer(struct crec *crecp)
239{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100240 if (!(crecp->flags & F_CNAME))
241 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100242
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100243 /* NB. record may be reused as DS or DNSKEY, where uid is
244 overloaded for something completely different */
245 if (crecp->addr.cname.cache &&
Simon Kelley611ebc52012-07-16 16:23:46 +0100246 (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100247 crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100248 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100249
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100250 return 1;
251}
252
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000253static int is_expired(time_t now, struct crec *crecp)
254{
255 if (crecp->flags & F_IMMORTAL)
256 return 0;
257
258 if (difftime(now, crecp->ttd) < 0)
259 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100260
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000261 return 1;
262}
263
264static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000265{
266 /* Scan and remove old entries.
267 If (flags & F_FORWARD) then remove any forward entries for name and any expired
268 entries but only in the same hash bucket as name.
269 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
270 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000271 If (flags == 0) remove any expired entries in the whole cache.
272
273 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000274 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000275
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000276 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
277 so that when we hit an entry which isn't reverse and is immortal, we're done. */
278
279 struct crec *crecp, **up;
280
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000281 if (flags & F_FORWARD)
282 {
Simon Kelley6b010842007-02-12 20:32:07 +0000283 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000284 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
285 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000286 *up = crecp->hash_next;
287 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000288 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000289 cache_unlink(crecp);
290 cache_free(crecp);
291 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000292 }
293 else if ((crecp->flags & F_FORWARD) &&
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100294 ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000295 hostname_isequal(cache_get_name(crecp), name))
296 {
297 if (crecp->flags & (F_HOSTS | F_DHCP))
298 return 0;
299 *up = crecp->hash_next;
300 cache_unlink(crecp);
301 cache_free(crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000302 }
303 else
304 up = &crecp->hash_next;
305 }
306 else
307 {
308 int i;
309#ifdef HAVE_IPV6
310 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
311#else
312 int addrlen = INADDRSZ;
313#endif
314 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000315 for (crecp = hash_table[i], up = &hash_table[i];
316 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
317 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000318 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000319 {
320 *up = crecp->hash_next;
321 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
322 {
323 cache_unlink(crecp);
324 cache_free(crecp);
325 }
326 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000327 else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
328 (flags & crecp->flags & F_REVERSE) &&
329 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
330 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
331 {
332 *up = crecp->hash_next;
333 cache_unlink(crecp);
334 cache_free(crecp);
335 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000336 else
337 up = &crecp->hash_next;
338 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000339
340 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000341}
342
343/* Note: The normal calling sequence is
344 cache_start_insert
345 cache_insert * n
346 cache_end_insert
347
348 but an abort can cause the cache_end_insert to be missed
349 in which can the next cache_start_insert cleans things up. */
350
351void cache_start_insert(void)
352{
353 /* Free any entries which didn't get committed during the last
354 insert due to error.
355 */
356 while (new_chain)
357 {
358 struct crec *tmp = new_chain->next;
359 cache_free(new_chain);
360 new_chain = tmp;
361 }
362 new_chain = NULL;
363 insert_error = 0;
364}
365
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100366struct crec *cache_insert(char *name, struct all_addr *addr,
367 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000368{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000369 struct crec *new;
370 union bigname *big_name = NULL;
371 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100372 int free_avail = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000373
Simon Kelley1d860412012-09-20 20:48:04 +0100374 if(daemon->max_cache_ttl < ttl)
375 ttl = daemon->max_cache_ttl;
376
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100377 /* Don't log keys */
378 if (flags & (F_IPV4 | F_IPV6))
379 log_query(flags | F_UPSTREAM, name, addr, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000380
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000381 /* if previous insertion failed give up now. */
382 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100383 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000384
385 /* First remove any expired entries and entries for the name/address we
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000386 are currently inserting. Fail is we attempt to delete a name from
387 /etc/hosts or DHCP. */
388 if (!cache_scan_free(name, addr, now, flags))
389 {
390 insert_error = 1;
391 return NULL;
392 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000393
394 /* Now get a cache entry from the end of the LRU list */
395 while (1) {
396 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
397 {
398 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100399 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000400 }
401
402 /* End of LRU list is still in use: if we didn't scan all the hash
403 chains for expired entries do that now. If we already tried that
404 then it's time to start spilling things. */
405
406 if (new->flags & (F_FORWARD | F_REVERSE))
407 {
Simon Kelley9e038942008-05-30 20:06:34 +0100408 /* If free_avail set, we believe that an entry has been freed.
409 Bugs have been known to make this not true, resulting in
Simon Kelley1a6bca82008-07-11 11:11:42 +0100410 a tight loop here. If that happens, abandon the
Simon Kelley9e038942008-05-30 20:06:34 +0100411 insert. Once in this state, all inserts will probably fail. */
Simon Kelley9e038942008-05-30 20:06:34 +0100412 if (free_avail)
413 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100414 insert_error = 1;
Simon Kelley9e038942008-05-30 20:06:34 +0100415 return NULL;
416 }
417
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 if (freed_all)
419 {
Simon Kelley9e038942008-05-30 20:06:34 +0100420 free_avail = 1; /* Must be free space now. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100421 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000422 cache_live_freed++;
423 }
424 else
425 {
426 cache_scan_free(NULL, NULL, now, 0);
427 freed_all = 1;
428 }
429 continue;
430 }
431
432 /* Check if we need to and can allocate extra memory for a long name.
433 If that fails, give up now. */
434 if (name && (strlen(name) > SMALLDNAME-1))
435 {
436 if (big_free)
437 {
438 big_name = big_free;
439 big_free = big_free->next;
440 }
441 else if (!bignames_left ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100442 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000443 {
444 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100445 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446 }
447 else
448 bignames_left--;
449
450 }
451
452 /* Got the rest: finally grab entry. */
453 cache_unlink(new);
454 break;
455 }
456
457 new->flags = flags;
458 if (big_name)
459 {
460 new->name.bname = big_name;
461 new->flags |= F_BIGNAME;
462 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100463
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000464 if (name)
465 strcpy(cache_get_name(new), name);
466 else
467 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100468
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000469 if (addr)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100470 new->addr.addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100471
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472 new->ttd = now + (time_t)ttl;
473 new->next = new_chain;
474 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100475
476 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000477}
478
479/* after end of insertion, commit the new entries */
480void cache_end_insert(void)
481{
482 if (insert_error)
483 return;
484
485 while (new_chain)
486 {
487 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100488 /* drop CNAMEs which didn't find a target. */
489 if (is_outdated_cname_pointer(new_chain))
490 cache_free(new_chain);
491 else
492 {
493 cache_hash(new_chain);
494 cache_link(new_chain);
495 cache_inserted++;
496 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000497 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000498 }
499 new_chain = NULL;
500}
501
502struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
503{
504 struct crec *ans;
505
506 if (crecp) /* iterating */
507 ans = crecp->next;
508 else
509 {
510 /* first search, look for relevant entries and push to top of list
511 also free anything which has expired */
512 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000513 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000514
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000515 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
516 {
517 next = crecp->hash_next;
518
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000519 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000520 {
521 if ((crecp->flags & F_FORWARD) &&
522 (crecp->flags & prot) &&
523 hostname_isequal(cache_get_name(crecp), name))
524 {
525 if (crecp->flags & (F_HOSTS | F_DHCP))
526 {
527 *chainp = crecp;
528 chainp = &crecp->next;
529 }
530 else
531 {
532 cache_unlink(crecp);
533 cache_link(crecp);
534 }
535
Simon Kelley824af852008-02-12 20:43:05 +0000536 /* Move all but the first entry up the hash chain
537 this implements round-robin.
538 Make sure that re-ordering doesn't break the hash-chain
539 order invariants.
540 */
Simon Kelley9e038942008-05-30 20:06:34 +0100541 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000542 {
543 *up = crecp->hash_next;
544 crecp->hash_next = *insert;
545 *insert = crecp;
546 insert = &crecp->hash_next;
547 }
Simon Kelley9e038942008-05-30 20:06:34 +0100548 else
549 {
550 if (!insert)
551 {
552 insert = up;
553 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
554 }
555 up = &crecp->hash_next;
556 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000557 }
558 else
559 /* case : not expired, incorrect entry. */
560 up = &crecp->hash_next;
561 }
562 else
563 {
564 /* expired entry, free it */
565 *up = crecp->hash_next;
566 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
567 {
568 cache_unlink(crecp);
569 cache_free(crecp);
570 }
571 }
572 }
573
574 *chainp = cache_head;
575 }
576
577 if (ans &&
578 (ans->flags & F_FORWARD) &&
579 (ans->flags & prot) &&
580 hostname_isequal(cache_get_name(ans), name))
581 return ans;
582
583 return NULL;
584}
585
586struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
587 time_t now, unsigned short prot)
588{
589 struct crec *ans;
590#ifdef HAVE_IPV6
591 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
592#else
593 int addrlen = INADDRSZ;
594#endif
595
596 if (crecp) /* iterating */
597 ans = crecp->next;
598 else
599 {
600 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000601 also free anything which has expired. All the reverse entries are at the
602 start of the hash chain, so we can give up when we find the first
603 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000604 int i;
605 struct crec **up, **chainp = &ans;
606
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000607 for (i=0; i<hash_size; i++)
608 for (crecp = hash_table[i], up = &hash_table[i];
609 crecp && (crecp->flags & F_REVERSE);
610 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000611 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000612 {
Simon Kelley6b010842007-02-12 20:32:07 +0000613 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100614 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000615 {
616 if (crecp->flags & (F_HOSTS | F_DHCP))
617 {
618 *chainp = crecp;
619 chainp = &crecp->next;
620 }
621 else
622 {
623 cache_unlink(crecp);
624 cache_link(crecp);
625 }
626 }
627 up = &crecp->hash_next;
628 }
629 else
630 {
631 *up = crecp->hash_next;
632 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
633 {
634 cache_unlink(crecp);
635 cache_free(crecp);
636 }
637 }
638
639 *chainp = cache_head;
640 }
641
642 if (ans &&
643 (ans->flags & F_REVERSE) &&
644 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100645 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000646 return ans;
647
648 return NULL;
649}
650
Simon Kelley611ebc52012-07-16 16:23:46 +0100651static void add_hosts_cname(struct crec *target)
652{
653 struct crec *crec;
654 struct cname *a;
655
656 for (a = daemon->cnames; a; a = a->next)
657 if (hostname_isequal(cache_get_name(target), a->target) &&
658 (crec = whine_malloc(sizeof(struct crec))))
659 {
660 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
661 crec->name.namep = a->alias;
662 crec->addr.cname.cache = target;
663 crec->addr.cname.uid = target->uid;
664 cache_hash(crec);
665 add_hosts_cname(crec); /* handle chains */
666 }
667}
668
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100669static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelleye759d422012-03-16 13:18:57 +0000670 int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000671{
Simon Kelleye759d422012-03-16 13:18:57 +0000672 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 +0000673 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000674 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000675
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000676 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000677 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000678 {
Simon Kelley9009d742008-11-14 20:04:27 +0000679 nameexists = 1;
680 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
681 {
682 free(cache);
683 return;
684 }
685 }
686
687 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000688 We do this by steam here, The entries are kept in hash chains, linked
689 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000690 the array rhash, hashed on address. Note that rhash and the values
691 in ->next are only valid whilst reading hosts files: the buckets are
692 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000693
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000694 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000695
696 This complexity avoids O(n^2) divergent CPU use whilst reading
697 large (10000 entry) hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000698
Simon Kelley205fafa2012-01-11 21:31:51 +0000699 /* hash address */
700 for (j = 0, i = 0; i < addrlen; i++)
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000701 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
Simon Kelley915363f2012-01-11 22:00:48 +0000702
703 for (lookup = rhash[j]; lookup; lookup = lookup->next)
Simon Kelleye759d422012-03-16 13:18:57 +0000704 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelley205fafa2012-01-11 21:31:51 +0000705 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
Simon Kelley9009d742008-11-14 20:04:27 +0000706 {
Simon Kelleye759d422012-03-16 13:18:57 +0000707 cache->flags &= ~F_REVERSE;
Simon Kelley205fafa2012-01-11 21:31:51 +0000708 break;
Simon Kelley9009d742008-11-14 20:04:27 +0000709 }
710
Simon Kelley915363f2012-01-11 22:00:48 +0000711 /* maintain address hash chain, insert new unique address */
712 if (!lookup)
713 {
714 cache->next = rhash[j];
715 rhash[j] = cache;
716 }
717
Simon Kelley9009d742008-11-14 20:04:27 +0000718 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000719 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000720 cache_hash(cache);
721
722 /* don't need to do alias stuff for second and subsequent addresses. */
723 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100724 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000725}
726
727static int eatspace(FILE *f)
728{
729 int c, nl = 0;
730
731 while (1)
732 {
733 if ((c = getc(f)) == '#')
734 while (c != '\n' && c != EOF)
735 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000736
Simon Kelley9009d742008-11-14 20:04:27 +0000737 if (c == EOF)
738 return 1;
739
740 if (!isspace(c))
741 {
742 ungetc(c, f);
743 return nl;
744 }
745
746 if (c == '\n')
747 nl = 1;
748 }
749}
750
751static int gettok(FILE *f, char *token)
752{
753 int c, count = 0;
754
755 while (1)
756 {
757 if ((c = getc(f)) == EOF)
758 return (count == 0) ? EOF : 1;
759
760 if (isspace(c) || c == '#')
761 {
762 ungetc(c, f);
763 return eatspace(f);
764 }
765
766 if (count < (MAXDNAME - 1))
767 {
768 token[count++] = c;
769 token[count] = 0;
770 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000771 }
772}
773
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000774static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000775{
776 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000777 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100778 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000779 unsigned short flags = 0;
780 struct all_addr addr;
781 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100782
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000783 if (!f)
784 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100785 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
Simon Kelley4011c4e2006-10-28 16:26:19 +0100786 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000787 }
Simon Kelley9009d742008-11-14 20:04:27 +0000788
789 eatspace(f);
790
791 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000792 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000793 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000794
Simon Kelley3d8df262005-08-29 12:19:27 +0100795 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000796 {
797 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
798 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000799 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000800 }
Simon Kelleye759d422012-03-16 13:18:57 +0000801#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100802 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000803 {
804 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
805 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000806 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000807 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000808#endif
809 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000810 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100811 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000812 while (atnl == 0)
813 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000814 continue;
815 }
Simon Kelley9009d742008-11-14 20:04:27 +0000816
Simon Kelley9009d742008-11-14 20:04:27 +0000817 addr_count++;
818
819 /* rehash every 1000 names. */
820 if ((name_count - cache_size) > 1000)
821 {
822 rehash(name_count);
823 cache_size = name_count;
824 }
825
826 while (atnl == 0)
827 {
828 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100829 int fqdn, nomem;
830 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000831
832 if ((atnl = gettok(f, token)) == EOF)
833 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000834
Simon Kelley9009d742008-11-14 20:04:27 +0000835 fqdn = !!strchr(token, '.');
836
Simon Kelley1f15b812009-10-13 17:49:32 +0100837 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000838 {
839 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000840 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000841 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100842 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000843 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100844 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000845 strcat(cache->name.sname, ".");
846 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000847 cache->flags = flags;
848 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000849 name_count++;
850 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100851 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000852 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100853 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000854 cache->flags = flags;
855 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000856 name_count++;
857 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100858 free(canon);
859
Simon Kelley9009d742008-11-14 20:04:27 +0000860 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100861 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +0000862 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
863 }
864 }
865
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000866 fclose(f);
Simon Kelley4011c4e2006-10-28 16:26:19 +0100867 rehash(name_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000868
Simon Kelleyf2621c72007-04-29 19:47:21 +0100869 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000870
Simon Kelley4011c4e2006-10-28 16:26:19 +0100871 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872}
873
Simon Kelley7622fc02009-06-04 20:32:05 +0100874void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000875{
876 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000877 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +0100878 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +0000879 struct host_record *hr;
880 struct name_list *nl;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000881
Simon Kelley59353a62004-11-21 19:34:28 +0000882 cache_inserted = cache_live_freed = 0;
883
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000884 for (i=0; i<hash_size; i++)
885 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
886 {
887 tmp = cache->hash_next;
888 if (cache->flags & F_HOSTS)
889 {
890 *up = cache->hash_next;
891 free(cache);
892 }
893 else if (!(cache->flags & F_DHCP))
894 {
895 *up = cache->hash_next;
896 if (cache->flags & F_BIGNAME)
897 {
898 cache->name.bname->next = big_free;
899 big_free = cache->name.bname;
900 }
901 cache->flags = 0;
902 }
903 else
904 up = &cache->hash_next;
905 }
906
Simon Kelleye759d422012-03-16 13:18:57 +0000907 /* borrow the packet buffer for a temporary by-address hash */
908 memset(daemon->packet, 0, daemon->packet_buff_sz);
909 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
910 /* we overwrote the buffer... */
911 daemon->srv_save = NULL;
912
913 /* Do host_records in config. */
914 for (hr = daemon->host_records; hr; hr = hr->next)
915 for (nl = hr->names; nl; nl = nl->next)
916 {
917 if (hr->addr.s_addr != 0 &&
918 (cache = whine_malloc(sizeof(struct crec))))
919 {
920 cache->name.namep = nl->name;
921 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
922 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
923 }
924#ifdef HAVE_IPV6
925 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
926 (cache = whine_malloc(sizeof(struct crec))))
927 {
928 cache->name.namep = nl->name;
929 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
930 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
931 }
932#endif
933 }
934
Simon Kelley28866e92011-02-14 20:19:14 +0000935 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100938 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939 return;
940 }
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000941
Simon Kelley28866e92011-02-14 20:19:14 +0000942 if (!option_bool(OPT_NO_HOSTS))
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000943 total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley28866e92011-02-14 20:19:14 +0000944
945 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
Simon Kelley7622fc02009-06-04 20:32:05 +0100946 for (ah = daemon->addn_hosts; ah; ah = ah->next)
947 if (!(ah->flags & AH_INACTIVE))
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000948 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000949}
950
Simon Kelley7622fc02009-06-04 20:32:05 +0100951char *get_domain(struct in_addr addr)
952{
953 struct cond_domain *c;
954
955 for (c = daemon->cond_domain; c; c = c->next)
Simon Kelleyd74942a2012-02-07 20:51:56 +0000956 if (!c->is6 &&
957 ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
Simon Kelley7622fc02009-06-04 20:32:05 +0100958 ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
959 return c->domain;
960
961 return daemon->domain_suffix;
962}
963
Simon Kelley4cb1b322012-02-06 14:30:41 +0000964
965#ifdef HAVE_IPV6
966char *get_domain6(struct in6_addr *addr)
967{
Simon Kelleyd74942a2012-02-07 20:51:56 +0000968 struct cond_domain *c;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000969
970 u64 addrpart = addr6part(addr);
971
Simon Kelleyd74942a2012-02-07 20:51:56 +0000972 for (c = daemon->cond_domain; c; c = c->next)
973 if (c->is6 &&
974 is_same_net6(addr, &c->start6, 64) &&
975 addrpart >= addr6part(&c->start6) &&
976 addrpart <= addr6part(&c->end6))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000977 return c->domain;
978
979 return daemon->domain_suffix;
980}
981#endif
982
Simon Kelley7622fc02009-06-04 20:32:05 +0100983#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +0100984struct in_addr a_record_from_hosts(char *name, time_t now)
985{
986 struct crec *crecp = NULL;
987 struct in_addr ret;
988
989 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
990 if (crecp->flags & F_HOSTS)
991 return *(struct in_addr *)&crecp->addr;
992
993 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
994
995 ret.s_addr = 0;
996 return ret;
997}
998
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000999void cache_unhash_dhcp(void)
1000{
Simon Kelley6b010842007-02-12 20:32:07 +00001001 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001002 int i;
1003
1004 for (i=0; i<hash_size; i++)
1005 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1006 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001007 {
1008 *up = cache->hash_next;
1009 cache->next = dhcp_spare;
1010 dhcp_spare = cache;
1011 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001012 else
1013 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001014}
1015
Simon Kelley611ebc52012-07-16 16:23:46 +01001016static void add_dhcp_cname(struct crec *target, time_t ttd)
1017{
1018 struct crec *aliasc;
1019 struct cname *a;
1020
1021 for (a = daemon->cnames; a; a = a->next)
1022 if (hostname_isequal(cache_get_name(target), a->target))
1023 {
1024 if ((aliasc = dhcp_spare))
1025 dhcp_spare = dhcp_spare->next;
1026 else /* need new one */
1027 aliasc = whine_malloc(sizeof(struct crec));
1028
1029 if (aliasc)
1030 {
1031 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
1032 if (ttd == 0)
1033 aliasc->flags |= F_IMMORTAL;
1034 else
1035 aliasc->ttd = ttd;
1036 aliasc->name.namep = a->alias;
1037 aliasc->addr.cname.cache = target;
1038 aliasc->addr.cname.uid = target->uid;
1039 cache_hash(aliasc);
1040 add_dhcp_cname(aliasc, ttd);
1041 }
1042 }
1043}
1044
Simon Kelley4cb1b322012-02-06 14:30:41 +00001045void cache_add_dhcp_entry(char *host_name, int prot,
1046 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001047{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001048 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001049 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001050 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001051 size_t addrlen = sizeof(struct in_addr);
1052
1053#ifdef HAVE_IPV6
1054 if (prot == AF_INET6)
1055 {
1056 flags = F_IPV6;
1057 addrlen = sizeof(struct in6_addr);
1058 }
1059#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001060
Simon Kelley12d71ed2012-08-30 15:16:41 +01001061 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1062
Simon Kelley4cb1b322012-02-06 14:30:41 +00001063 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001064 {
Simon Kelley824af852008-02-12 20:43:05 +00001065 /* check all addresses associated with name */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001066 if (crec->flags & F_HOSTS)
Simon Kelley1ab84e22004-01-29 16:48:35 +00001067 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001068 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001069 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001070 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001071 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001072 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1073 in_hosts = 1;
1074 else
1075 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001076 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001077 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001078 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001079 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001080 /* scan_free deletes all addresses associated with name */
1081 break;
1082 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001083 }
Simon Kelley824af852008-02-12 20:43:05 +00001084
Simon Kelley12d71ed2012-08-30 15:16:41 +01001085 /* if in hosts, don't need DHCP record */
1086 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001087 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001088
1089 /* Name in hosts, address doesn't match */
1090 if (fail_crec)
1091 {
1092 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1093 my_syslog(MS_DHCP | LOG_WARNING,
1094 _("not giving name %s to the DHCP lease of %s because "
1095 "the name exists in %s with address %s"),
1096 host_name, daemon->addrbuff,
1097 record_source(fail_crec->uid), daemon->namebuff);
1098 return;
1099 }
1100
1101 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1102 {
1103 if (crec->flags & F_NEG)
1104 {
1105 flags |= F_REVERSE;
1106 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1107 }
1108 }
1109 else
1110 flags |= F_REVERSE;
1111
1112 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001113 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001114 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001115 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001116
1117 if (crec) /* malloc may fail */
1118 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001119 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001120 if (ttd == 0)
1121 crec->flags |= F_IMMORTAL;
1122 else
1123 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001124 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001125 crec->name.namep = host_name;
Simon Kelley9009d742008-11-14 20:04:27 +00001126 crec->uid = uid++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001127 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001128
Simon Kelley611ebc52012-07-16 16:23:46 +01001129 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001130 }
1131}
Simon Kelley7622fc02009-06-04 20:32:05 +01001132#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001133
Simon Kelley9009d742008-11-14 20:04:27 +00001134
Simon Kelley5aabfc72007-08-29 11:24:47 +01001135void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001136{
Simon Kelley824af852008-02-12 20:43:05 +00001137 struct server *serv, *serv1;
1138
1139 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1140 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1141 daemon->cachesize, cache_live_freed, cache_inserted);
1142 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1143 daemon->queries_forwarded, daemon->local_answer);
1144
Simon Kelley824af852008-02-12 20:43:05 +00001145 /* sum counts from different records for same server */
1146 for (serv = daemon->servers; serv; serv = serv->next)
1147 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001148
Simon Kelley824af852008-02-12 20:43:05 +00001149 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001150 if (!(serv->flags &
1151 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001152 {
1153 int port;
1154 unsigned int queries = 0, failed_queries = 0;
1155 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001156 if (!(serv1->flags &
1157 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1158 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001159 {
1160 serv1->flags |= SERV_COUNTED;
1161 queries += serv1->queries;
1162 failed_queries += serv1->failed_queries;
1163 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001164 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1165 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 +00001166 }
1167
Simon Kelley28866e92011-02-14 20:19:14 +00001168 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001169 {
1170 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001171 int i;
Simon Kelley28866e92011-02-14 20:19:14 +00001172 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001173
1174 for (i=0; i<hash_size; i++)
1175 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1176 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001177 char *a, *p = daemon->namebuff;
1178 p += sprintf(p, "%-40.40s ", cache_get_name(cache));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001179 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001180 a = "";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001181 else if (cache->flags & F_CNAME)
1182 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001183 a = "";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001184 if (!is_outdated_cname_pointer(cache))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001185 a = cache_get_name(cache->addr.cname.cache);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001186 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001187#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001188 else if (cache->flags & F_DNSKEY)
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001189 {
1190 a = daemon->addrbuff;
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001191 sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);
1192 }
1193 else if (cache->flags & F_DS)
1194 {
1195 a = daemon->addrbuff;
1196 sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,
1197 cache->addr.key.algo, cache->addr.key.digest, cache->uid);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001198 }
1199#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001200 else
1201 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001202 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001203 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001204 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001205#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001206 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001207 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001208#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001209 }
1210
1211 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 +01001212 cache->flags & F_IPV4 ? "4" : "",
1213 cache->flags & F_IPV6 ? "6" : "",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001214 cache->flags & F_DNSKEY ? "K" : "",
1215 cache->flags & F_DS ? "S" : "",
Simon Kelleyf2621c72007-04-29 19:47:21 +01001216 cache->flags & F_CNAME ? "C" : "",
1217 cache->flags & F_FORWARD ? "F" : " ",
1218 cache->flags & F_REVERSE ? "R" : " ",
1219 cache->flags & F_IMMORTAL ? "I" : " ",
1220 cache->flags & F_DHCP ? "D" : " ",
1221 cache->flags & F_NEG ? "N" : " ",
1222 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001223 cache->flags & F_HOSTS ? "H" : " ",
1224 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001225#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001226 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001227#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001228 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1229 /* ctime includes trailing \n - eat it */
1230 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001231#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001232 my_syslog(LOG_INFO, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001233 }
1234 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001235}
1236
Simon Kelley7622fc02009-06-04 20:32:05 +01001237char *record_source(int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001238{
Simon Kelley7622fc02009-06-04 20:32:05 +01001239 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001240
Simon Kelley7622fc02009-06-04 20:32:05 +01001241 if (index == 0)
1242 return HOSTSFILE;
1243
1244 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1245 if (ah->index == index)
1246 return ah->fname;
1247
1248 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001249}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001250
Simon Kelley1a6bca82008-07-11 11:11:42 +01001251void querystr(char *str, unsigned short type)
1252{
1253 unsigned int i;
1254
1255 sprintf(str, "query[type=%d]", type);
1256 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1257 if (typestr[i].type == type)
1258 sprintf(str,"query[%s]", typestr[i].name);
1259}
1260
Simon Kelley28866e92011-02-14 20:19:14 +00001261void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001262{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001263 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001264 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001265
Simon Kelley28866e92011-02-14 20:19:14 +00001266 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001267 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001268
1269 if (addr)
1270 {
1271#ifdef HAVE_IPV6
1272 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
Simon Kelleyc72daea2012-01-05 21:33:27 +00001273 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001274#else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001275 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001276#endif
1277 }
1278
1279 if (flags & F_REVERSE)
1280 {
1281 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001282 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001283 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001284
1285 if (flags & F_NEG)
1286 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001287 if (flags & F_NXDOMAIN)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001288 {
1289 if (flags & F_IPV4)
1290 dest = "NXDOMAIN-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001291 else if (flags & F_IPV6)
1292 dest = "NXDOMAIN-IPv6";
1293 else
1294 dest = "NXDOMAIN";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001295 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001296 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001297 {
1298 if (flags & F_IPV4)
1299 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001300 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001301 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001302 else
1303 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001304 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001305 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001306 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001307 dest = "<CNAME>";
1308 else if (flags & F_RRNAME)
1309 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001310
Simon Kelley1f15b812009-10-13 17:49:32 +01001311 if (flags & F_CONFIG)
1312 source = "config";
1313 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001314 source = "DHCP";
1315 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001316 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317 else if (flags & F_UPSTREAM)
1318 source = "reply";
1319 else if (flags & F_SERVER)
1320 {
1321 source = "forwarded";
1322 verb = "to";
1323 }
1324 else if (flags & F_QUERY)
1325 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001326 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001327 verb = "from";
1328 }
1329 else
1330 source = "cached";
1331
Simon Kelley3d8df262005-08-29 12:19:27 +01001332 if (strlen(name) == 0)
1333 name = ".";
1334
Simon Kelley28866e92011-02-14 20:19:14 +00001335 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001336}
1337
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001338#ifdef HAVE_DNSSEC
1339struct keydata *keydata_alloc(char *data, size_t len)
1340{
1341 struct keydata *block, *ret = NULL;
1342 struct keydata **prev = &ret;
1343 while (len > 0)
1344 {
1345 if (keyblock_free)
1346 {
1347 block = keyblock_free;
1348 keyblock_free = block->next;
1349 }
1350 else
1351 block = whine_malloc(sizeof(struct keydata));
1352
1353 if (!block)
1354 {
1355 /* failed to alloc, free partial chain */
1356 keydata_free(ret);
1357 return NULL;
1358 }
1359
1360 memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len);
1361 data += KEYBLOCK_LEN;
1362 len -= KEYBLOCK_LEN;
1363 *prev = block;
1364 prev = &block->next;
1365 block->next = NULL;
1366 }
1367
1368 return ret;
1369}
1370
1371void keydata_free(struct keydata *blocks)
1372{
1373 struct keydata *tmp;
1374
1375 if (blocks)
1376 {
1377 for (tmp = blocks; tmp->next; tmp = tmp->next);
1378 tmp->next = keyblock_free;
1379 keyblock_free = blocks;
1380 }
1381}
1382#endif
1383
1384