Annotation of embedaddon/dnsmasq/src/cache.c, revision 1.1.1.1
1.1 misho 1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
20: #ifdef HAVE_DHCP
21: static struct crec *dhcp_spare = NULL;
22: #endif
23: static struct crec *new_chain = NULL;
24: static int cache_inserted = 0, cache_live_freed = 0, insert_error;
25: static union bigname *big_free = NULL;
26: static int bignames_left, hash_size;
27: static int uid = 0;
28: #ifdef HAVE_DNSSEC
29: static struct keydata *keyblock_free = NULL;
30: #endif
31:
32: /* type->string mapping: this is also used by the name-hash function as a mixing table. */
33: static 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" },
53: { 35, "NAPTR" },
54: { 36, "KX" },
55: { 37, "CERT" },
56: { 38, "A6" },
57: { 39, "DNAME" },
58: { 41, "OPT" },
59: { 48, "DNSKEY" },
60: { 249, "TKEY" },
61: { 250, "TSIG" },
62: { 251, "IXFR" },
63: { 252, "AXFR" },
64: { 253, "MAILB" },
65: { 254, "MAILA" },
66: { 255, "ANY" }
67: };
68:
69: static void cache_free(struct crec *crecp);
70: static void cache_unlink(struct crec *crecp);
71: static void cache_link(struct crec *crecp);
72: static void rehash(int size);
73: static void cache_hash(struct crec *crecp);
74:
75: void cache_init(void)
76: {
77: struct crec *crecp;
78: int i;
79:
80: bignames_left = daemon->cachesize/10;
81:
82: if (daemon->cachesize > 0)
83: {
84: crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
85:
86: for (i=0; i < daemon->cachesize; i++, crecp++)
87: {
88: cache_link(crecp);
89: crecp->flags = 0;
90: crecp->uid = uid++;
91: }
92: }
93:
94: /* create initial hash table*/
95: rehash(daemon->cachesize);
96: }
97:
98: /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
99: but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
100: will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
101: expand the table. */
102: static 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 *));
113: else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
114: 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:
136: static struct crec **hash_bucket(char *name)
137: {
138: unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
139: const unsigned char *mix_tab = (const unsigned char*)typestr;
140:
141: while((c = (unsigned char) *name++))
142: {
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';
146: val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
147: }
148:
149: /* hash_size is a power of two */
150: return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
151: }
152:
153: static void cache_hash(struct crec *crecp)
154: {
155: /* maintain an invariant that all entries with F_REVERSE set
156: are at the start of the hash-chain and all non-reverse
157: immortal entries are at the end of the hash-chain.
158: This allows reverse searches and garbage collection to be optimised */
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)
168: while (*up && !((*up)->flags & F_IMMORTAL))
169: up = &((*up)->hash_next);
170: }
171: crecp->hash_next = *up;
172: *up = crecp;
173: }
174:
175: static void cache_free(struct crec *crecp)
176: {
177: crecp->flags &= ~F_FORWARD;
178: crecp->flags &= ~F_REVERSE;
179: crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
180:
181: 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: }
196: #ifdef HAVE_DNSSEC
197: else if (crecp->flags & (F_DNSKEY | F_DS))
198: keydata_free(crecp->addr.key.keydata);
199: #endif
200: }
201:
202: /* insert a new cache entry at the head of the list (youngest entry) */
203: static 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 */
215: static 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:
228: char *cache_get_name(struct crec *crecp)
229: {
230: if (crecp->flags & F_BIGNAME)
231: return crecp->name.bname->name;
232: else if (crecp->flags & F_NAMEP)
233: return crecp->name.namep;
234:
235: return crecp->name.sname;
236: }
237:
238: struct 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:
261: static int is_outdated_cname_pointer(struct crec *crecp)
262: {
263: if (!(crecp->flags & F_CNAME))
264: return 0;
265:
266: /* NB. record may be reused as DS or DNSKEY, where uid is
267: overloaded for something completely different */
268: if (crecp->addr.cname.cache &&
269: (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
270: crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
271: return 0;
272:
273: return 1;
274: }
275:
276: static 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;
283:
284: return 1;
285: }
286:
287: static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
288: {
289: /* Scan and remove old entries.
290: If (flags & F_FORWARD) then remove any forward entries for name and any expired
291: entries but only in the same hash bucket as name.
292: If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
293: entries in the whole cache.
294: If (flags == 0) remove any expired entries in the whole cache.
295:
296: In the flags & F_FORWARD case, the return code is valid, and returns zero if the
297: name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
298:
299: We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
300: so that when we hit an entry which isn't reverse and is immortal, we're done. */
301:
302: struct crec *crecp, **up;
303:
304: if (flags & F_FORWARD)
305: {
306: for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
307: if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
308: {
309: *up = crecp->hash_next;
310: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
311: {
312: cache_unlink(crecp);
313: cache_free(crecp);
314: }
315: }
316: else if ((crecp->flags & F_FORWARD) &&
317: ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&
318: hostname_isequal(cache_get_name(crecp), name))
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);
325: }
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++)
338: for (crecp = hash_table[i], up = &hash_table[i];
339: crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
340: crecp = crecp->hash_next)
341: if (is_expired(now, crecp))
342: {
343: *up = crecp->hash_next;
344: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
345: {
346: cache_unlink(crecp);
347: cache_free(crecp);
348: }
349: }
350: else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
351: (flags & crecp->flags & F_REVERSE) &&
352: (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
353: memcmp(&crecp->addr.addr, addr, addrlen) == 0)
354: {
355: *up = crecp->hash_next;
356: cache_unlink(crecp);
357: cache_free(crecp);
358: }
359: else
360: up = &crecp->hash_next;
361: }
362:
363: return 1;
364: }
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:
374: void 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:
389: struct crec *cache_insert(char *name, struct all_addr *addr,
390: time_t now, unsigned long ttl, unsigned short flags)
391: {
392: struct crec *new;
393: union bigname *big_name = NULL;
394: int freed_all = flags & F_REVERSE;
395: int free_avail = 0;
396:
397: if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
398: ttl = daemon->max_cache_ttl;
399:
400: /* Don't log keys */
401: if (flags & (F_IPV4 | F_IPV6))
402: log_query(flags | F_UPSTREAM, name, addr, NULL);
403:
404: /* if previous insertion failed give up now. */
405: if (insert_error)
406: return NULL;
407:
408: /* First remove any expired entries and entries for the name/address we
409: are currently inserting. Fail is we attempt to delete a name from
410: /etc/hosts or DHCP. */
411: if (!cache_scan_free(name, addr, now, flags))
412: {
413: insert_error = 1;
414: return NULL;
415: }
416:
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;
422: return NULL;
423: }
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: {
431: /* If free_avail set, we believe that an entry has been freed.
432: Bugs have been known to make this not true, resulting in
433: a tight loop here. If that happens, abandon the
434: insert. Once in this state, all inserts will probably fail. */
435: if (free_avail)
436: {
437: insert_error = 1;
438: return NULL;
439: }
440:
441: if (freed_all)
442: {
443: free_avail = 1; /* Must be free space now. */
444: cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
445: 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 ||
465: !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
466: {
467: insert_error = 1;
468: return NULL;
469: }
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: }
486:
487: if (name)
488: strcpy(cache_get_name(new), name);
489: else
490: *cache_get_name(new) = 0;
491:
492: if (addr)
493: new->addr.addr = *addr;
494:
495: new->ttd = now + (time_t)ttl;
496: new->next = new_chain;
497: new_chain = new;
498:
499: return new;
500: }
501:
502: /* after end of insertion, commit the new entries */
503: void cache_end_insert(void)
504: {
505: if (insert_error)
506: return;
507:
508: while (new_chain)
509: {
510: struct crec *tmp = new_chain->next;
511: /* drop CNAMEs which didn't find a target. */
512: if (is_outdated_cname_pointer(new_chain))
513: cache_free(new_chain);
514: else
515: {
516: cache_hash(new_chain);
517: cache_link(new_chain);
518: cache_inserted++;
519: }
520: new_chain = tmp;
521: }
522: new_chain = NULL;
523: }
524:
525: struct 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;
536: unsigned short ins_flags = 0;
537:
538: for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
539: {
540: next = crecp->hash_next;
541:
542: if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
543: {
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:
559: /* Move all but the first entry up the hash chain
560: this implements round-robin.
561: Make sure that re-ordering doesn't break the hash-chain
562: order invariants.
563: */
564: if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
565: {
566: *up = crecp->hash_next;
567: crecp->hash_next = *insert;
568: *insert = crecp;
569: insert = &crecp->hash_next;
570: }
571: 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: }
580: }
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:
609: struct 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
624: also free anything which has expired. All the reverse entries are at the
625: start of the hash chain, so we can give up when we find the first
626: non-REVERSE one. */
627: int i;
628: struct crec **up, **chainp = &ans;
629:
630: for (i=0; i<hash_size; i++)
631: for (crecp = hash_table[i], up = &hash_table[i];
632: crecp && (crecp->flags & F_REVERSE);
633: crecp = crecp->hash_next)
634: if (!is_expired(now, crecp))
635: {
636: if ((crecp->flags & prot) &&
637: memcmp(&crecp->addr.addr, addr, addrlen) == 0)
638: {
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) &&
668: memcmp(&ans->addr.addr, addr, addrlen) == 0)
669: return ans;
670:
671: return NULL;
672: }
673:
674: static 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:
692: static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
693: int index, struct crec **rhash, int hashsz)
694: {
695: struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
696: int i, nameexists = 0;
697: unsigned int j;
698:
699: /* Remove duplicates in hosts files. */
700: if (lookup && (lookup->flags & F_HOSTS))
701: {
702: 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)
711: We do this by steam here, The entries are kept in hash chains, linked
712: by ->next (which is unused at this point) held in hash buckets in
713: the array rhash, hashed on address. Note that rhash and the values
714: in ->next are only valid whilst reading hosts files: the buckets are
715: then freed, and the ->next pointer used for other things.
716:
717: Only insert each unique address once into this hashing structure.
718:
719: This complexity avoids O(n^2) divergent CPU use whilst reading
720: large (10000 entry) hosts files. */
721:
722: /* hash address */
723: for (j = 0, i = 0; i < addrlen; i++)
724: j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
725:
726: for (lookup = rhash[j]; lookup; lookup = lookup->next)
727: if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
728: memcmp(&lookup->addr.addr, addr, addrlen) == 0)
729: {
730: cache->flags &= ~F_REVERSE;
731: break;
732: }
733:
734: /* maintain address hash chain, insert new unique address */
735: if (!lookup)
736: {
737: cache->next = rhash[j];
738: rhash[j] = cache;
739: }
740:
741: cache->uid = index;
742: memcpy(&cache->addr.addr, addr, addrlen);
743: cache_hash(cache);
744:
745: /* don't need to do alias stuff for second and subsequent addresses. */
746: if (!nameexists)
747: add_hosts_cname(cache);
748: }
749:
750: static 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);
759:
760: 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:
774: static 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: }
794: }
795: }
796:
797: static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
798: {
799: FILE *f = fopen(filename, "r");
800: char *token = daemon->namebuff, *domain_suffix = NULL;
801: int addr_count = 0, name_count = cache_size, lineno = 0;
802: unsigned short flags = 0;
803: struct all_addr addr;
804: int atnl, addrlen = 0;
805:
806: if (!f)
807: {
808: my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
809: return 0;
810: }
811:
812: eatspace(f);
813:
814: while ((atnl = gettok(f, token)) != EOF)
815: {
816: lineno++;
817:
818: if (inet_pton(AF_INET, token, &addr) > 0)
819: {
820: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
821: addrlen = INADDRSZ;
822: domain_suffix = get_domain(addr.addr.addr4);
823: }
824: #ifdef HAVE_IPV6
825: else if (inet_pton(AF_INET6, token, &addr) > 0)
826: {
827: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
828: addrlen = IN6ADDRSZ;
829: domain_suffix = get_domain6(&addr.addr.addr6);
830: }
831: #endif
832: else
833: {
834: my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
835: while (atnl == 0)
836: atnl = gettok(f, token);
837: continue;
838: }
839:
840: 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;
852: int fqdn, nomem;
853: char *canon;
854:
855: if ((atnl = gettok(f, token)) == EOF)
856: break;
857:
858: fqdn = !!strchr(token, '.');
859:
860: if ((canon = canonicalise(token, &nomem)))
861: {
862: /* If set, add a version of the name with a default domain appended */
863: if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
864: (cache = whine_malloc(sizeof(struct crec) +
865: strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
866: {
867: strcpy(cache->name.sname, canon);
868: strcat(cache->name.sname, ".");
869: strcat(cache->name.sname, domain_suffix);
870: cache->flags = flags;
871: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
872: name_count++;
873: }
874: if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
875: {
876: strcpy(cache->name.sname, canon);
877: cache->flags = flags;
878: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
879: name_count++;
880: }
881: free(canon);
882:
883: }
884: else if (!nomem)
885: my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
886: }
887: }
888:
889: fclose(f);
890: rehash(name_count);
891:
892: my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
893:
894: return name_count;
895: }
896:
897: void cache_reload(void)
898: {
899: struct crec *cache, **up, *tmp;
900: int revhashsz, i, total_size = daemon->cachesize;
901: struct hostsfile *ah;
902: struct host_record *hr;
903: struct name_list *nl;
904:
905: cache_inserted = cache_live_freed = 0;
906:
907: 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:
930: /* borrow the packet buffer for a temporary by-address hash */
931: memset(daemon->packet, 0, daemon->packet_buff_sz);
932: revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
933: /* we overwrote the buffer... */
934: daemon->srv_save = NULL;
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:
958: if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
959: {
960: if (daemon->cachesize > 0)
961: my_syslog(LOG_INFO, _("cleared cache"));
962: return;
963: }
964:
965: if (!option_bool(OPT_NO_HOSTS))
966: total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
967:
968: daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
969: for (ah = daemon->addn_hosts; ah; ah = ah->next)
970: if (!(ah->flags & AH_INACTIVE))
971: total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
972: }
973:
974: char *get_domain(struct in_addr addr)
975: {
976: struct cond_domain *c;
977:
978: for (c = daemon->cond_domain; c; c = c->next)
979: if (!c->is6 &&
980: ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
981: ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
982: return c->domain;
983:
984: return daemon->domain_suffix;
985: }
986:
987:
988: #ifdef HAVE_IPV6
989: char *get_domain6(struct in6_addr *addr)
990: {
991: struct cond_domain *c;
992:
993: u64 addrpart = addr6part(addr);
994:
995: for (c = daemon->cond_domain; c; c = c->next)
996: if (c->is6 &&
997: is_same_net6(addr, &c->start6, 64) &&
998: addrpart >= addr6part(&c->start6) &&
999: addrpart <= addr6part(&c->end6))
1000: return c->domain;
1001:
1002: return daemon->domain_suffix;
1003: }
1004: #endif
1005:
1006: #ifdef HAVE_DHCP
1007: struct in_addr a_record_from_hosts(char *name, time_t now)
1008: {
1009: struct crec *crecp = NULL;
1010: struct in_addr ret;
1011:
1012: while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1013: if (crecp->flags & F_HOSTS)
1014: return *(struct in_addr *)&crecp->addr;
1015:
1016: my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1017:
1018: ret.s_addr = 0;
1019: return ret;
1020: }
1021:
1022: void cache_unhash_dhcp(void)
1023: {
1024: struct crec *cache, **up;
1025: int i;
1026:
1027: for (i=0; i<hash_size; i++)
1028: for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1029: if (cache->flags & F_DHCP)
1030: {
1031: *up = cache->hash_next;
1032: cache->next = dhcp_spare;
1033: dhcp_spare = cache;
1034: }
1035: else
1036: up = &cache->hash_next;
1037: }
1038:
1039: static void add_dhcp_cname(struct crec *target, time_t ttd)
1040: {
1041: struct crec *aliasc;
1042: struct cname *a;
1043:
1044: for (a = daemon->cnames; a; a = a->next)
1045: if (hostname_isequal(cache_get_name(target), a->target))
1046: {
1047: if ((aliasc = dhcp_spare))
1048: dhcp_spare = dhcp_spare->next;
1049: else /* need new one */
1050: aliasc = whine_malloc(sizeof(struct crec));
1051:
1052: if (aliasc)
1053: {
1054: aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
1055: if (ttd == 0)
1056: aliasc->flags |= F_IMMORTAL;
1057: else
1058: aliasc->ttd = ttd;
1059: aliasc->name.namep = a->alias;
1060: aliasc->addr.cname.cache = target;
1061: aliasc->addr.cname.uid = target->uid;
1062: cache_hash(aliasc);
1063: add_dhcp_cname(aliasc, ttd);
1064: }
1065: }
1066: }
1067:
1068: void cache_add_dhcp_entry(char *host_name, int prot,
1069: struct all_addr *host_address, time_t ttd)
1070: {
1071: struct crec *crec = NULL, *fail_crec = NULL;
1072: unsigned short flags = F_IPV4;
1073: int in_hosts = 0;
1074: size_t addrlen = sizeof(struct in_addr);
1075:
1076: #ifdef HAVE_IPV6
1077: if (prot == AF_INET6)
1078: {
1079: flags = F_IPV6;
1080: addrlen = sizeof(struct in6_addr);
1081: }
1082: #endif
1083:
1084: inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1085:
1086: while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
1087: {
1088: /* check all addresses associated with name */
1089: if (crec->flags & F_HOSTS)
1090: {
1091: if (crec->flags & F_CNAME)
1092: my_syslog(MS_DHCP | LOG_WARNING,
1093: _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1094: host_name, daemon->addrbuff);
1095: else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1096: in_hosts = 1;
1097: else
1098: fail_crec = crec;
1099: }
1100: else if (!(crec->flags & F_DHCP))
1101: {
1102: cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
1103: /* scan_free deletes all addresses associated with name */
1104: break;
1105: }
1106: }
1107:
1108: /* if in hosts, don't need DHCP record */
1109: if (in_hosts)
1110: return;
1111:
1112: /* Name in hosts, address doesn't match */
1113: if (fail_crec)
1114: {
1115: inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1116: my_syslog(MS_DHCP | LOG_WARNING,
1117: _("not giving name %s to the DHCP lease of %s because "
1118: "the name exists in %s with address %s"),
1119: host_name, daemon->addrbuff,
1120: record_source(fail_crec->uid), daemon->namebuff);
1121: return;
1122: }
1123:
1124: if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1125: {
1126: if (crec->flags & F_NEG)
1127: {
1128: flags |= F_REVERSE;
1129: cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1130: }
1131: }
1132: else
1133: flags |= F_REVERSE;
1134:
1135: if ((crec = dhcp_spare))
1136: dhcp_spare = dhcp_spare->next;
1137: else /* need new one */
1138: crec = whine_malloc(sizeof(struct crec));
1139:
1140: if (crec) /* malloc may fail */
1141: {
1142: crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
1143: if (ttd == 0)
1144: crec->flags |= F_IMMORTAL;
1145: else
1146: crec->ttd = ttd;
1147: crec->addr.addr = *host_address;
1148: crec->name.namep = host_name;
1149: crec->uid = uid++;
1150: cache_hash(crec);
1151:
1152: add_dhcp_cname(crec, ttd);
1153: }
1154: }
1155: #endif
1156:
1157:
1158: void dump_cache(time_t now)
1159: {
1160: struct server *serv, *serv1;
1161:
1162: my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1163: my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1164: daemon->cachesize, cache_live_freed, cache_inserted);
1165: my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1166: daemon->queries_forwarded, daemon->local_answer);
1167:
1168: /* sum counts from different records for same server */
1169: for (serv = daemon->servers; serv; serv = serv->next)
1170: serv->flags &= ~SERV_COUNTED;
1171:
1172: for (serv = daemon->servers; serv; serv = serv->next)
1173: if (!(serv->flags &
1174: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1175: {
1176: int port;
1177: unsigned int queries = 0, failed_queries = 0;
1178: for (serv1 = serv; serv1; serv1 = serv1->next)
1179: if (!(serv1->flags &
1180: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1181: sockaddr_isequal(&serv->addr, &serv1->addr))
1182: {
1183: serv1->flags |= SERV_COUNTED;
1184: queries += serv1->queries;
1185: failed_queries += serv1->failed_queries;
1186: }
1187: port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1188: my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
1189: }
1190:
1191: if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
1192: {
1193: struct crec *cache ;
1194: int i;
1195: my_syslog(LOG_INFO, "Host Address Flags Expires");
1196:
1197: for (i=0; i<hash_size; i++)
1198: for (cache = hash_table[i]; cache; cache = cache->hash_next)
1199: {
1200: char *a, *p = daemon->namebuff;
1201: p += sprintf(p, "%-40.40s ", cache_get_name(cache));
1202: if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
1203: a = "";
1204: else if (cache->flags & F_CNAME)
1205: {
1206: a = "";
1207: if (!is_outdated_cname_pointer(cache))
1208: a = cache_get_name(cache->addr.cname.cache);
1209: }
1210: #ifdef HAVE_DNSSEC
1211: else if (cache->flags & F_DNSKEY)
1212: {
1213: a = daemon->addrbuff;
1214: sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);
1215: }
1216: else if (cache->flags & F_DS)
1217: {
1218: a = daemon->addrbuff;
1219: sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,
1220: cache->addr.key.algo, cache->addr.key.digest, cache->uid);
1221: }
1222: #endif
1223: else
1224: {
1225: a = daemon->addrbuff;
1226: if (cache->flags & F_IPV4)
1227: inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
1228: #ifdef HAVE_IPV6
1229: else if (cache->flags & F_IPV6)
1230: inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
1231: #endif
1232: }
1233:
1234: p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a,
1235: cache->flags & F_IPV4 ? "4" : "",
1236: cache->flags & F_IPV6 ? "6" : "",
1237: cache->flags & F_DNSKEY ? "K" : "",
1238: cache->flags & F_DS ? "S" : "",
1239: cache->flags & F_CNAME ? "C" : "",
1240: cache->flags & F_FORWARD ? "F" : " ",
1241: cache->flags & F_REVERSE ? "R" : " ",
1242: cache->flags & F_IMMORTAL ? "I" : " ",
1243: cache->flags & F_DHCP ? "D" : " ",
1244: cache->flags & F_NEG ? "N" : " ",
1245: cache->flags & F_NXDOMAIN ? "X" : " ",
1246: cache->flags & F_HOSTS ? "H" : " ",
1247: cache->flags & F_DNSSECOK ? "V" : " ");
1248: #ifdef HAVE_BROKEN_RTC
1249: p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1250: #else
1251: p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1252: /* ctime includes trailing \n - eat it */
1253: *(p-1) = 0;
1254: #endif
1255: my_syslog(LOG_INFO, daemon->namebuff);
1256: }
1257: }
1258: }
1259:
1260: char *record_source(int index)
1261: {
1262: struct hostsfile *ah;
1263:
1264: if (index == 0)
1265: return HOSTSFILE;
1266:
1267: for (ah = daemon->addn_hosts; ah; ah = ah->next)
1268: if (ah->index == index)
1269: return ah->fname;
1270:
1271: return "<unknown>";
1272: }
1273:
1274: void querystr(char *desc, char *str, unsigned short type)
1275: {
1276: unsigned int i;
1277:
1278: sprintf(str, "%s[type=%d]", desc, type);
1279: for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1280: if (typestr[i].type == type)
1281: sprintf(str,"%s[%s]", desc, typestr[i].name);
1282: }
1283:
1284: void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
1285: {
1286: char *source, *dest = daemon->addrbuff;
1287: char *verb = "is";
1288:
1289: if (!option_bool(OPT_LOG))
1290: return;
1291:
1292: if (addr)
1293: {
1294: #ifdef HAVE_IPV6
1295: inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1296: addr, daemon->addrbuff, ADDRSTRLEN);
1297: #else
1298: strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1299: #endif
1300: }
1301:
1302: if (flags & F_REVERSE)
1303: {
1304: dest = name;
1305: name = daemon->addrbuff;
1306: }
1307:
1308: if (flags & F_NEG)
1309: {
1310: if (flags & F_NXDOMAIN)
1311: {
1312: if (flags & F_IPV4)
1313: dest = "NXDOMAIN-IPv4";
1314: else if (flags & F_IPV6)
1315: dest = "NXDOMAIN-IPv6";
1316: else
1317: dest = "NXDOMAIN";
1318: }
1319: else
1320: {
1321: if (flags & F_IPV4)
1322: dest = "NODATA-IPv4";
1323: else if (flags & F_IPV6)
1324: dest = "NODATA-IPv6";
1325: else
1326: dest = "NODATA";
1327: }
1328: }
1329: else if (flags & F_CNAME)
1330: dest = "<CNAME>";
1331: else if (flags & F_RRNAME)
1332: dest = arg;
1333:
1334: if (flags & F_CONFIG)
1335: source = "config";
1336: else if (flags & F_DHCP)
1337: source = "DHCP";
1338: else if (flags & F_HOSTS)
1339: source = arg;
1340: else if (flags & F_UPSTREAM)
1341: source = "reply";
1342: else if (flags & F_AUTH)
1343: source = "auth";
1344: else if (flags & F_SERVER)
1345: {
1346: source = "forwarded";
1347: verb = "to";
1348: }
1349: else if (flags & F_QUERY)
1350: {
1351: source = arg;
1352: verb = "from";
1353: }
1354: else
1355: source = "cached";
1356:
1357: if (strlen(name) == 0)
1358: name = ".";
1359:
1360: my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
1361: }
1362:
1363: #ifdef HAVE_DNSSEC
1364: struct keydata *keydata_alloc(char *data, size_t len)
1365: {
1366: struct keydata *block, *ret = NULL;
1367: struct keydata **prev = &ret;
1368: while (len > 0)
1369: {
1370: if (keyblock_free)
1371: {
1372: block = keyblock_free;
1373: keyblock_free = block->next;
1374: }
1375: else
1376: block = whine_malloc(sizeof(struct keydata));
1377:
1378: if (!block)
1379: {
1380: /* failed to alloc, free partial chain */
1381: keydata_free(ret);
1382: return NULL;
1383: }
1384:
1385: memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len);
1386: data += KEYBLOCK_LEN;
1387: len -= KEYBLOCK_LEN;
1388: *prev = block;
1389: prev = &block->next;
1390: block->next = NULL;
1391: }
1392:
1393: return ret;
1394: }
1395:
1396: void keydata_free(struct keydata *blocks)
1397: {
1398: struct keydata *tmp;
1399:
1400: if (blocks)
1401: {
1402: for (tmp = blocks; tmp->next; tmp = tmp->next);
1403: tmp->next = keyblock_free;
1404: keyblock_free = blocks;
1405: }
1406: }
1407: #endif
1408:
1409:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>