Annotation of embedaddon/dnsmasq/src/cache.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
1.1 misho 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;
1.1.1.4 ! misho 24: static int insert_error;
1.1 misho 25: static union bigname *big_free = NULL;
26: static int bignames_left, hash_size;
27:
1.1.1.4 ! misho 28: static void make_non_terminals(struct crec *source);
! 29: static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
! 30: time_t now, unsigned long ttl, unsigned int flags);
! 31:
1.1 misho 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" },
1.1.1.4 ! misho 52: { 29, "LOC" },
1.1 misho 53: { 33, "SRV" },
54: { 35, "NAPTR" },
55: { 36, "KX" },
56: { 37, "CERT" },
57: { 38, "A6" },
58: { 39, "DNAME" },
59: { 41, "OPT" },
1.1.1.2 misho 60: { 43, "DS" },
61: { 46, "RRSIG" },
62: { 47, "NSEC" },
1.1 misho 63: { 48, "DNSKEY" },
1.1.1.2 misho 64: { 50, "NSEC3" },
1.1.1.4 ! misho 65: { 51, "NSEC3PARAM" },
! 66: { 52, "TLSA" },
! 67: { 53, "SMIMEA" },
! 68: { 55, "HIP" },
1.1 misho 69: { 249, "TKEY" },
70: { 250, "TSIG" },
71: { 251, "IXFR" },
72: { 252, "AXFR" },
73: { 253, "MAILB" },
74: { 254, "MAILA" },
1.1.1.4 ! misho 75: { 255, "ANY" },
! 76: { 257, "CAA" }
1.1 misho 77: };
78:
79: static void cache_free(struct crec *crecp);
80: static void cache_unlink(struct crec *crecp);
81: static void cache_link(struct crec *crecp);
82: static void rehash(int size);
83: static void cache_hash(struct crec *crecp);
84:
1.1.1.4 ! misho 85: void next_uid(struct crec *crecp)
1.1.1.2 misho 86: {
87: static unsigned int uid = 0;
88:
1.1.1.4 ! misho 89: if (crecp->uid == UID_NONE)
! 90: {
! 91: uid++;
1.1.1.2 misho 92:
1.1.1.4 ! misho 93: /* uid == 0 used to indicate CNAME to interface name. */
! 94: if (uid == UID_NONE)
! 95: uid++;
! 96:
! 97: crecp->uid = uid;
! 98: }
1.1.1.2 misho 99: }
100:
1.1 misho 101: void cache_init(void)
102: {
103: struct crec *crecp;
104: int i;
1.1.1.2 misho 105:
1.1 misho 106: bignames_left = daemon->cachesize/10;
107:
108: if (daemon->cachesize > 0)
109: {
110: crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
111:
112: for (i=0; i < daemon->cachesize; i++, crecp++)
113: {
114: cache_link(crecp);
115: crecp->flags = 0;
1.1.1.4 ! misho 116: crecp->uid = UID_NONE;
1.1 misho 117: }
118: }
119:
120: /* create initial hash table*/
121: rehash(daemon->cachesize);
122: }
123:
124: /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
125: but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
126: will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
127: expand the table. */
128: static void rehash(int size)
129: {
130: struct crec **new, **old, *p, *tmp;
131: int i, new_size, old_size;
132:
133: /* hash_size is a power of two. */
134: for (new_size = 64; new_size < size/10; new_size = new_size << 1);
135:
136: /* must succeed in getting first instance, failure later is non-fatal */
137: if (!hash_table)
138: new = safe_malloc(new_size * sizeof(struct crec *));
139: else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
140: return;
141:
142: for(i = 0; i < new_size; i++)
143: new[i] = NULL;
144:
145: old = hash_table;
146: old_size = hash_size;
147: hash_table = new;
148: hash_size = new_size;
149:
150: if (old)
151: {
152: for (i = 0; i < old_size; i++)
153: for (p = old[i]; p ; p = tmp)
154: {
155: tmp = p->hash_next;
156: cache_hash(p);
157: }
158: free(old);
159: }
160: }
161:
162: static struct crec **hash_bucket(char *name)
163: {
164: unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
165: const unsigned char *mix_tab = (const unsigned char*)typestr;
166:
167: while((c = (unsigned char) *name++))
168: {
169: /* don't use tolower and friends here - they may be messed up by LOCALE */
170: if (c >= 'A' && c <= 'Z')
171: c += 'a' - 'A';
172: val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
173: }
174:
175: /* hash_size is a power of two */
176: return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
177: }
178:
179: static void cache_hash(struct crec *crecp)
180: {
181: /* maintain an invariant that all entries with F_REVERSE set
182: are at the start of the hash-chain and all non-reverse
183: immortal entries are at the end of the hash-chain.
184: This allows reverse searches and garbage collection to be optimised */
185:
186: struct crec **up = hash_bucket(cache_get_name(crecp));
187:
188: if (!(crecp->flags & F_REVERSE))
189: {
190: while (*up && ((*up)->flags & F_REVERSE))
191: up = &((*up)->hash_next);
192:
193: if (crecp->flags & F_IMMORTAL)
194: while (*up && !((*up)->flags & F_IMMORTAL))
195: up = &((*up)->hash_next);
196: }
197: crecp->hash_next = *up;
198: *up = crecp;
199: }
1.1.1.2 misho 200:
201: static void cache_blockdata_free(struct crec *crecp)
202: {
1.1.1.4 ! misho 203: if (!(crecp->flags & F_NEG))
! 204: {
! 205: if (crecp->flags & F_SRV)
! 206: blockdata_free(crecp->addr.srv.target);
! 207: #ifdef HAVE_DNSSEC
! 208: else if (crecp->flags & F_DNSKEY)
! 209: blockdata_free(crecp->addr.key.keydata);
! 210: else if (crecp->flags & F_DS)
! 211: blockdata_free(crecp->addr.ds.keydata);
1.1.1.2 misho 212: #endif
1.1.1.4 ! misho 213: }
! 214: }
1.1.1.2 misho 215:
1.1 misho 216: static void cache_free(struct crec *crecp)
217: {
218: crecp->flags &= ~F_FORWARD;
219: crecp->flags &= ~F_REVERSE;
1.1.1.4 ! misho 220: crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
1.1.1.2 misho 221:
1.1 misho 222: if (cache_tail)
223: cache_tail->next = crecp;
224: else
225: cache_head = crecp;
226: crecp->prev = cache_tail;
227: crecp->next = NULL;
228: cache_tail = crecp;
229:
230: /* retrieve big name for further use. */
231: if (crecp->flags & F_BIGNAME)
232: {
233: crecp->name.bname->next = big_free;
234: big_free = crecp->name.bname;
235: crecp->flags &= ~F_BIGNAME;
236: }
1.1.1.2 misho 237:
238: cache_blockdata_free(crecp);
1.1 misho 239: }
240:
241: /* insert a new cache entry at the head of the list (youngest entry) */
242: static void cache_link(struct crec *crecp)
243: {
244: if (cache_head) /* check needed for init code */
245: cache_head->prev = crecp;
246: crecp->next = cache_head;
247: crecp->prev = NULL;
248: cache_head = crecp;
249: if (!cache_tail)
250: cache_tail = crecp;
251: }
252:
253: /* remove an arbitrary cache entry for promotion */
254: static void cache_unlink (struct crec *crecp)
255: {
256: if (crecp->prev)
257: crecp->prev->next = crecp->next;
258: else
259: cache_head = crecp->next;
260:
261: if (crecp->next)
262: crecp->next->prev = crecp->prev;
263: else
264: cache_tail = crecp->prev;
265: }
266:
267: char *cache_get_name(struct crec *crecp)
268: {
269: if (crecp->flags & F_BIGNAME)
270: return crecp->name.bname->name;
271: else if (crecp->flags & F_NAMEP)
272: return crecp->name.namep;
273:
274: return crecp->name.sname;
275: }
276:
1.1.1.2 misho 277: char *cache_get_cname_target(struct crec *crecp)
278: {
1.1.1.4 ! misho 279: if (crecp->addr.cname.is_name_ptr)
! 280: return crecp->addr.cname.target.name;
! 281: else
1.1.1.2 misho 282: return cache_get_name(crecp->addr.cname.target.cache);
283: }
284:
285:
286:
1.1 misho 287: struct crec *cache_enumerate(int init)
288: {
289: static int bucket;
290: static struct crec *cache;
291:
292: if (init)
293: {
294: bucket = 0;
295: cache = NULL;
296: }
297: else if (cache && cache->hash_next)
298: cache = cache->hash_next;
299: else
300: {
301: cache = NULL;
302: while (bucket < hash_size)
303: if ((cache = hash_table[bucket++]))
304: break;
305: }
306:
307: return cache;
308: }
309:
310: static int is_outdated_cname_pointer(struct crec *crecp)
311: {
1.1.1.4 ! misho 312: if (!(crecp->flags & F_CNAME) || crecp->addr.cname.is_name_ptr)
1.1 misho 313: return 0;
314:
315: /* NB. record may be reused as DS or DNSKEY, where uid is
316: overloaded for something completely different */
1.1.1.2 misho 317: if (crecp->addr.cname.target.cache &&
1.1.1.4 ! misho 318: !(crecp->addr.cname.target.cache->flags & (F_DNSKEY | F_DS)) &&
1.1.1.2 misho 319: crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
1.1 misho 320: return 0;
321:
322: return 1;
323: }
324:
325: static int is_expired(time_t now, struct crec *crecp)
326: {
327: if (crecp->flags & F_IMMORTAL)
328: return 0;
329:
330: if (difftime(now, crecp->ttd) < 0)
331: return 0;
332:
333: return 1;
334: }
335:
1.1.1.4 ! misho 336: static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
! 337: unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
1.1 misho 338: {
339: /* Scan and remove old entries.
340: If (flags & F_FORWARD) then remove any forward entries for name and any expired
341: entries but only in the same hash bucket as name.
342: If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
343: entries in the whole cache.
344: If (flags == 0) remove any expired entries in the whole cache.
345:
1.1.1.3 misho 346: In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
347: to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
1.1 misho 348:
349: We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
1.1.1.4 ! misho 350: so that when we hit an entry which isn't reverse and is immortal, we're done.
! 351:
! 352: If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
! 353: This entry will get re-used with the same name, to preserve CNAMEs. */
1.1 misho 354:
355: struct crec *crecp, **up;
1.1.1.4 ! misho 356:
! 357: (void)class;
1.1 misho 358:
359: if (flags & F_FORWARD)
360: {
361: for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
1.1.1.2 misho 362: {
363: if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
364: {
365: /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
1.1.1.4 ! misho 366: if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
1.1.1.2 misho 367: (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
368: {
369: if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
1.1.1.3 misho 370: return crecp;
1.1.1.2 misho 371: *up = crecp->hash_next;
1.1.1.4 ! misho 372: /* If this record is for the name we're inserting and is the target
! 373: of a CNAME record. Make the new record for the same name, in the same
! 374: crec, with the same uid to avoid breaking the existing CNAME. */
! 375: if (crecp->uid != UID_NONE)
! 376: {
! 377: if (target_crec)
! 378: *target_crec = crecp;
! 379: if (target_uid)
! 380: *target_uid = crecp->uid;
! 381: }
1.1.1.2 misho 382: cache_unlink(crecp);
383: cache_free(crecp);
384: continue;
385: }
386:
387: #ifdef HAVE_DNSSEC
1.1.1.3 misho 388: /* Deletion has to be class-sensitive for DS and DNSKEY */
1.1.1.4 ! misho 389: if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == class)
1.1.1.2 misho 390: {
391: if (crecp->flags & F_CONFIG)
1.1.1.3 misho 392: return crecp;
1.1.1.2 misho 393: *up = crecp->hash_next;
394: cache_unlink(crecp);
395: cache_free(crecp);
396: continue;
397: }
398: #endif
399: }
1.1.1.4 ! misho 400:
! 401: if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
! 402: {
! 403: *up = crecp->hash_next;
! 404: if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
! 405: {
! 406: cache_unlink(crecp);
! 407: cache_free(crecp);
! 408: }
! 409: continue;
! 410: }
! 411:
1.1 misho 412: up = &crecp->hash_next;
1.1.1.2 misho 413: }
1.1 misho 414: }
415: else
416: {
417: int i;
418: int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
1.1.1.4 ! misho 419:
1.1 misho 420: for (i = 0; i < hash_size; i++)
421: for (crecp = hash_table[i], up = &hash_table[i];
422: crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
423: crecp = crecp->hash_next)
424: if (is_expired(now, crecp))
425: {
426: *up = crecp->hash_next;
1.1.1.2 misho 427: if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1.1 misho 428: {
429: cache_unlink(crecp);
430: cache_free(crecp);
431: }
432: }
1.1.1.2 misho 433: else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
1.1 misho 434: (flags & crecp->flags & F_REVERSE) &&
435: (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
1.1.1.4 ! misho 436: memcmp(&crecp->addr, addr, addrlen) == 0)
1.1 misho 437: {
438: *up = crecp->hash_next;
439: cache_unlink(crecp);
440: cache_free(crecp);
441: }
442: else
443: up = &crecp->hash_next;
444: }
445:
1.1.1.3 misho 446: return NULL;
1.1 misho 447: }
448:
449: /* Note: The normal calling sequence is
450: cache_start_insert
451: cache_insert * n
452: cache_end_insert
453:
454: but an abort can cause the cache_end_insert to be missed
455: in which can the next cache_start_insert cleans things up. */
456:
457: void cache_start_insert(void)
458: {
459: /* Free any entries which didn't get committed during the last
460: insert due to error.
461: */
462: while (new_chain)
463: {
464: struct crec *tmp = new_chain->next;
465: cache_free(new_chain);
466: new_chain = tmp;
467: }
468: new_chain = NULL;
469: insert_error = 0;
470: }
471:
1.1.1.4 ! misho 472: struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
! 473: time_t now, unsigned long ttl, unsigned int flags)
! 474: {
! 475: #ifdef HAVE_DNSSEC
! 476: if (flags & (F_DNSKEY | F_DS))
! 477: {
! 478: /* The DNSSEC validation process works by getting needed records into the
! 479: cache, then retrying the validation until they are all in place.
! 480: This can be messed up by very short TTLs, and _really_ messed up by
! 481: zero TTLs, so we force the TTL to be at least long enough to do a validation.
! 482: Ideally, we should use some kind of reference counting so that records are
! 483: locked until the validation that asked for them is complete, but this
! 484: is much easier, and just as effective. */
! 485: if (ttl < DNSSEC_MIN_TTL)
! 486: ttl = DNSSEC_MIN_TTL;
! 487: }
! 488: else
! 489: #endif
1.1.1.2 misho 490: {
1.1.1.4 ! misho 491: /* Don't log DNSSEC records here, done elsewhere */
1.1.1.2 misho 492: log_query(flags | F_UPSTREAM, name, addr, NULL);
493: if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
494: ttl = daemon->max_cache_ttl;
1.1.1.3 misho 495: if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
496: ttl = daemon->min_cache_ttl;
1.1.1.4 ! misho 497: }
! 498:
! 499: return really_insert(name, addr, class, now, ttl, flags);
! 500: }
1.1 misho 501:
1.1.1.4 ! misho 502:
! 503: static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
! 504: time_t now, unsigned long ttl, unsigned int flags)
! 505: {
! 506: struct crec *new, *target_crec = NULL;
! 507: union bigname *big_name = NULL;
! 508: int freed_all = flags & F_REVERSE;
! 509: int free_avail = 0;
! 510: unsigned int target_uid;
! 511:
1.1 misho 512: /* if previous insertion failed give up now. */
513: if (insert_error)
514: return NULL;
1.1.1.4 ! misho 515:
! 516: /* we don't cache zero-TTL records. */
! 517: if (ttl == 0)
! 518: {
! 519: insert_error = 1;
! 520: return NULL;
! 521: }
1.1.1.2 misho 522:
1.1 misho 523: /* First remove any expired entries and entries for the name/address we
1.1.1.3 misho 524: are currently inserting. */
1.1.1.4 ! misho 525: if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid)))
1.1 misho 526: {
1.1.1.3 misho 527: /* We're trying to insert a record over one from
528: /etc/hosts or DHCP, or other config. If the
1.1.1.4 ! misho 529: existing record is for an A or AAAA or CNAME and
1.1.1.3 misho 530: the record we're trying to insert is the same,
531: just drop the insert, but don't error the whole process. */
532: if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
533: {
534: if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
1.1.1.4 ! misho 535: new->addr.addr4.s_addr == addr->addr4.s_addr)
1.1.1.3 misho 536: return new;
537: else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
1.1.1.4 ! misho 538: IN6_ARE_ADDR_EQUAL(&new->addr.addr6, &addr->addr6))
1.1.1.3 misho 539: return new;
540: }
1.1.1.4 ! misho 541:
1.1 misho 542: insert_error = 1;
543: return NULL;
544: }
545:
546: /* Now get a cache entry from the end of the LRU list */
1.1.1.4 ! misho 547: if (!target_crec)
! 548: while (1) {
! 549: if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
! 550: {
! 551: insert_error = 1;
! 552: return NULL;
! 553: }
! 554:
! 555: /* Free entry at end of LRU list, use it. */
! 556: if (!(new->flags & (F_FORWARD | F_REVERSE)))
! 557: break;
1.1.1.2 misho 558:
1.1.1.4 ! misho 559: /* End of LRU list is still in use: if we didn't scan all the hash
! 560: chains for expired entries do that now. If we already tried that
! 561: then it's time to start spilling things. */
! 562:
! 563: /* If free_avail set, we believe that an entry has been freed.
! 564: Bugs have been known to make this not true, resulting in
! 565: a tight loop here. If that happens, abandon the
! 566: insert. Once in this state, all inserts will probably fail. */
! 567: if (free_avail)
! 568: {
! 569: static int warned = 0;
! 570: if (!warned)
! 571: {
! 572: my_syslog(LOG_ERR, _("Internal error in cache."));
! 573: warned = 1;
! 574: }
! 575: insert_error = 1;
! 576: return NULL;
! 577: }
! 578:
! 579: if (freed_all)
! 580: {
! 581: /* For DNSSEC records, uid holds class. */
! 582: free_avail = 1; /* Must be free space now. */
! 583: cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL);
! 584: daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
! 585: }
! 586: else
! 587: {
! 588: cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
! 589: freed_all = 1;
! 590: }
! 591: }
! 592:
! 593: /* Check if we need to and can allocate extra memory for a long name.
! 594: If that fails, give up now, always succeed for DNSSEC records. */
! 595: if (name && (strlen(name) > SMALLDNAME-1))
! 596: {
! 597: if (big_free)
! 598: {
! 599: big_name = big_free;
! 600: big_free = big_free->next;
! 601: }
! 602: else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
! 603: !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
! 604: {
! 605: insert_error = 1;
! 606: return NULL;
! 607: }
! 608: else if (bignames_left != 0)
! 609: bignames_left--;
! 610:
! 611: }
1.1 misho 612:
1.1.1.4 ! misho 613: /* If we freed a cache entry for our name which was a CNAME target, use that.
! 614: and preserve the uid, so that existing CNAMES are not broken. */
! 615: if (target_crec)
! 616: {
! 617: new = target_crec;
! 618: new->uid = target_uid;
! 619: }
! 620:
! 621: /* Got the rest: finally grab entry. */
! 622: cache_unlink(new);
1.1 misho 623:
624: new->flags = flags;
625: if (big_name)
626: {
627: new->name.bname = big_name;
628: new->flags |= F_BIGNAME;
629: }
630:
631: if (name)
632: strcpy(cache_get_name(new), name);
633: else
634: *cache_get_name(new) = 0;
635:
1.1.1.2 misho 636: #ifdef HAVE_DNSSEC
1.1.1.4 ! misho 637: if (flags & (F_DS | F_DNSKEY))
! 638: new->uid = class;
1.1.1.2 misho 639: #endif
1.1.1.4 ! misho 640:
! 641: if (addr)
! 642: new->addr = *addr;
1.1 misho 643:
644: new->ttd = now + (time_t)ttl;
645: new->next = new_chain;
646: new_chain = new;
647:
648: return new;
649: }
650:
651: /* after end of insertion, commit the new entries */
652: void cache_end_insert(void)
653: {
654: if (insert_error)
655: return;
656:
657: while (new_chain)
658: {
659: struct crec *tmp = new_chain->next;
660: /* drop CNAMEs which didn't find a target. */
661: if (is_outdated_cname_pointer(new_chain))
662: cache_free(new_chain);
663: else
664: {
665: cache_hash(new_chain);
666: cache_link(new_chain);
1.1.1.4 ! misho 667: daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
! 668:
! 669: /* If we're a child process, send this cache entry up the pipe to the master.
! 670: The marshalling process is rather nasty. */
! 671: if (daemon->pipe_to_parent != -1)
! 672: {
! 673: char *name = cache_get_name(new_chain);
! 674: ssize_t m = strlen(name);
! 675: unsigned int flags = new_chain->flags;
! 676: #ifdef HAVE_DNSSEC
! 677: u16 class = new_chain->uid;
! 678: #endif
! 679:
! 680: read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
! 681: read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
! 682: read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
! 683: read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
! 684:
! 685: if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
! 686: read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
! 687: if (flags & F_SRV)
! 688: {
! 689: /* A negative SRV entry is possible and has no data, obviously. */
! 690: if (!(flags & F_NEG))
! 691: blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
! 692: }
! 693: #ifdef HAVE_DNSSEC
! 694: if (flags & F_DNSKEY)
! 695: {
! 696: read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
! 697: blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
! 698: }
! 699: else if (flags & F_DS)
! 700: {
! 701: read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
! 702: /* A negative DS entry is possible and has no data, obviously. */
! 703: if (!(flags & F_NEG))
! 704: blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
! 705: }
! 706: #endif
! 707: }
1.1 misho 708: }
1.1.1.4 ! misho 709:
1.1 misho 710: new_chain = tmp;
711: }
1.1.1.4 ! misho 712:
! 713: /* signal end of cache insert in master process */
! 714: if (daemon->pipe_to_parent != -1)
! 715: {
! 716: ssize_t m = -1;
! 717: read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
! 718: }
! 719:
1.1 misho 720: new_chain = NULL;
721: }
722:
1.1.1.4 ! misho 723:
! 724: /* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
! 725: int cache_recv_insert(time_t now, int fd)
! 726: {
! 727: ssize_t m;
! 728: union all_addr addr;
! 729: unsigned long ttl;
! 730: time_t ttd;
! 731: unsigned int flags;
! 732: struct crec *crecp = NULL;
! 733:
! 734: cache_start_insert();
! 735:
! 736: while(1)
! 737: {
! 738:
! 739: if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
! 740: return 0;
! 741:
! 742: if (m == -1)
! 743: {
! 744: cache_end_insert();
! 745: return 1;
! 746: }
! 747:
! 748: if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
! 749: !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
! 750: !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
! 751: return 0;
! 752:
! 753: daemon->namebuff[m] = 0;
! 754:
! 755: ttl = difftime(ttd, now);
! 756:
! 757: if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
! 758: {
! 759: unsigned short class = C_IN;
! 760:
! 761: if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
! 762: return 0;
! 763:
! 764: if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
! 765: return 0;
! 766:
! 767: #ifdef HAVE_DNSSEC
! 768: if (flags & F_DNSKEY)
! 769: {
! 770: if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
! 771: !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
! 772: return 0;
! 773: }
! 774: else if (flags & F_DS)
! 775: {
! 776: if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
! 777: (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
! 778: return 0;
! 779: }
! 780: #endif
! 781:
! 782: crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
! 783: }
! 784: else if (flags & F_CNAME)
! 785: {
! 786: struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
! 787: /* This relies on the fact that the target of a CNAME immediately precedes
! 788: it because of the order of extraction in extract_addresses, and
! 789: the order reversal on the new_chain. */
! 790: if (newc)
! 791: {
! 792: newc->addr.cname.is_name_ptr = 0;
! 793:
! 794: if (!crecp)
! 795: newc->addr.cname.target.cache = NULL;
! 796: else
! 797: {
! 798: next_uid(crecp);
! 799: newc->addr.cname.target.cache = crecp;
! 800: newc->addr.cname.uid = crecp->uid;
! 801: }
! 802: }
! 803: }
! 804: }
! 805: }
! 806:
! 807: int cache_find_non_terminal(char *name, time_t now)
! 808: {
! 809: struct crec *crecp;
! 810:
! 811: for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
! 812: if (!is_outdated_cname_pointer(crecp) &&
! 813: !is_expired(now, crecp) &&
! 814: (crecp->flags & F_FORWARD) &&
! 815: !(crecp->flags & F_NXDOMAIN) &&
! 816: hostname_isequal(name, cache_get_name(crecp)))
! 817: return 1;
! 818:
! 819: return 0;
! 820: }
! 821:
1.1.1.2 misho 822: struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
1.1 misho 823: {
824: struct crec *ans;
1.1.1.2 misho 825: int no_rr = prot & F_NO_RR;
1.1 misho 826:
1.1.1.2 misho 827: prot &= ~F_NO_RR;
828:
1.1 misho 829: if (crecp) /* iterating */
830: ans = crecp->next;
831: else
832: {
833: /* first search, look for relevant entries and push to top of list
834: also free anything which has expired */
835: struct crec *next, **up, **insert = NULL, **chainp = &ans;
1.1.1.4 ! misho 836: unsigned int ins_flags = 0;
1.1 misho 837:
838: for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
839: {
840: next = crecp->hash_next;
841:
842: if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
843: {
844: if ((crecp->flags & F_FORWARD) &&
845: (crecp->flags & prot) &&
846: hostname_isequal(cache_get_name(crecp), name))
847: {
1.1.1.2 misho 848: if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
1.1 misho 849: {
850: *chainp = crecp;
851: chainp = &crecp->next;
852: }
853: else
854: {
855: cache_unlink(crecp);
856: cache_link(crecp);
857: }
858:
859: /* Move all but the first entry up the hash chain
860: this implements round-robin.
861: Make sure that re-ordering doesn't break the hash-chain
862: order invariants.
863: */
864: if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
865: {
866: *up = crecp->hash_next;
867: crecp->hash_next = *insert;
868: *insert = crecp;
869: insert = &crecp->hash_next;
870: }
871: else
872: {
1.1.1.2 misho 873: if (!insert && !no_rr)
1.1 misho 874: {
875: insert = up;
876: ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
877: }
878: up = &crecp->hash_next;
879: }
880: }
881: else
882: /* case : not expired, incorrect entry. */
883: up = &crecp->hash_next;
884: }
885: else
886: {
887: /* expired entry, free it */
888: *up = crecp->hash_next;
1.1.1.2 misho 889: if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1.1 misho 890: {
891: cache_unlink(crecp);
892: cache_free(crecp);
893: }
894: }
895: }
896:
897: *chainp = cache_head;
898: }
899:
900: if (ans &&
901: (ans->flags & F_FORWARD) &&
1.1.1.2 misho 902: (ans->flags & prot) &&
1.1 misho 903: hostname_isequal(cache_get_name(ans), name))
904: return ans;
905:
906: return NULL;
907: }
908:
1.1.1.4 ! misho 909: struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
1.1.1.2 misho 910: time_t now, unsigned int prot)
1.1 misho 911: {
912: struct crec *ans;
913: int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
914:
915: if (crecp) /* iterating */
916: ans = crecp->next;
917: else
918: {
919: /* first search, look for relevant entries and push to top of list
920: also free anything which has expired. All the reverse entries are at the
921: start of the hash chain, so we can give up when we find the first
922: non-REVERSE one. */
923: int i;
924: struct crec **up, **chainp = &ans;
925:
926: for (i=0; i<hash_size; i++)
927: for (crecp = hash_table[i], up = &hash_table[i];
928: crecp && (crecp->flags & F_REVERSE);
929: crecp = crecp->hash_next)
930: if (!is_expired(now, crecp))
931: {
932: if ((crecp->flags & prot) &&
1.1.1.4 ! misho 933: memcmp(&crecp->addr, addr, addrlen) == 0)
1.1 misho 934: {
1.1.1.2 misho 935: if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
1.1 misho 936: {
937: *chainp = crecp;
938: chainp = &crecp->next;
939: }
940: else
941: {
942: cache_unlink(crecp);
943: cache_link(crecp);
944: }
945: }
946: up = &crecp->hash_next;
947: }
948: else
949: {
950: *up = crecp->hash_next;
1.1.1.2 misho 951: if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1.1 misho 952: {
953: cache_unlink(crecp);
954: cache_free(crecp);
955: }
956: }
957:
958: *chainp = cache_head;
959: }
960:
961: if (ans &&
962: (ans->flags & F_REVERSE) &&
963: (ans->flags & prot) &&
1.1.1.4 ! misho 964: memcmp(&ans->addr, addr, addrlen) == 0)
1.1 misho 965: return ans;
966:
967: return NULL;
968: }
969:
1.1.1.4 ! misho 970: static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
1.1.1.2 misho 971: unsigned int index, struct crec **rhash, int hashsz)
1.1 misho 972: {
973: struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
1.1.1.4 ! misho 974: int i;
1.1 misho 975: unsigned int j;
976:
977: /* Remove duplicates in hosts files. */
1.1.1.4 ! misho 978: if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
1.1 misho 979: {
1.1.1.4 ! misho 980: free(cache);
! 981: return;
1.1 misho 982: }
1.1.1.4 ! misho 983:
1.1 misho 984: /* Ensure there is only one address -> name mapping (first one trumps)
985: We do this by steam here, The entries are kept in hash chains, linked
986: by ->next (which is unused at this point) held in hash buckets in
987: the array rhash, hashed on address. Note that rhash and the values
988: in ->next are only valid whilst reading hosts files: the buckets are
989: then freed, and the ->next pointer used for other things.
990:
991: Only insert each unique address once into this hashing structure.
992:
993: This complexity avoids O(n^2) divergent CPU use whilst reading
1.1.1.3 misho 994: large (10000 entry) hosts files.
995:
996: Note that we only do this process when bulk-reading hosts files,
997: for incremental reads, rhash is NULL, and we use cache lookups
998: instead.
999: */
1.1 misho 1000:
1.1.1.3 misho 1001: if (rhash)
1.1 misho 1002: {
1.1.1.3 misho 1003: /* hash address */
1004: for (j = 0, i = 0; i < addrlen; i++)
1005: j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
1006:
1007: for (lookup = rhash[j]; lookup; lookup = lookup->next)
1008: if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
1.1.1.4 ! misho 1009: memcmp(&lookup->addr, addr, addrlen) == 0)
1.1.1.3 misho 1010: {
1011: cache->flags &= ~F_REVERSE;
1012: break;
1013: }
1014:
1015: /* maintain address hash chain, insert new unique address */
1016: if (!lookup)
1017: {
1018: cache->next = rhash[j];
1019: rhash[j] = cache;
1020: }
1.1 misho 1021: }
1.1.1.3 misho 1022: else
1023: {
1024: /* incremental read, lookup in cache */
1025: lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
1026: if (lookup && lookup->flags & F_HOSTS)
1027: cache->flags &= ~F_REVERSE;
1028: }
1029:
1.1 misho 1030: cache->uid = index;
1.1.1.4 ! misho 1031: memcpy(&cache->addr, addr, addrlen);
1.1 misho 1032: cache_hash(cache);
1.1.1.4 ! misho 1033: make_non_terminals(cache);
1.1 misho 1034: }
1035:
1036: static int eatspace(FILE *f)
1037: {
1038: int c, nl = 0;
1039:
1040: while (1)
1041: {
1042: if ((c = getc(f)) == '#')
1043: while (c != '\n' && c != EOF)
1044: c = getc(f);
1045:
1046: if (c == EOF)
1047: return 1;
1048:
1049: if (!isspace(c))
1050: {
1051: ungetc(c, f);
1052: return nl;
1053: }
1054:
1055: if (c == '\n')
1.1.1.4 ! misho 1056: nl++;
1.1 misho 1057: }
1058: }
1059:
1060: static int gettok(FILE *f, char *token)
1061: {
1062: int c, count = 0;
1063:
1064: while (1)
1065: {
1066: if ((c = getc(f)) == EOF)
1.1.1.4 ! misho 1067: return (count == 0) ? -1 : 1;
1.1 misho 1068:
1069: if (isspace(c) || c == '#')
1070: {
1071: ungetc(c, f);
1072: return eatspace(f);
1073: }
1074:
1075: if (count < (MAXDNAME - 1))
1076: {
1077: token[count++] = c;
1078: token[count] = 0;
1079: }
1080: }
1081: }
1082:
1.1.1.3 misho 1083: int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
1.1 misho 1084: {
1085: FILE *f = fopen(filename, "r");
1086: char *token = daemon->namebuff, *domain_suffix = NULL;
1.1.1.4 ! misho 1087: int addr_count = 0, name_count = cache_size, lineno = 1;
! 1088: unsigned int flags = 0;
! 1089: union all_addr addr;
1.1 misho 1090: int atnl, addrlen = 0;
1091:
1092: if (!f)
1093: {
1094: my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
1.1.1.3 misho 1095: return cache_size;
1.1 misho 1096: }
1097:
1.1.1.4 ! misho 1098: lineno += eatspace(f);
1.1 misho 1099:
1.1.1.4 ! misho 1100: while ((atnl = gettok(f, token)) != -1)
1.1 misho 1101: {
1102: if (inet_pton(AF_INET, token, &addr) > 0)
1103: {
1104: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
1105: addrlen = INADDRSZ;
1.1.1.4 ! misho 1106: domain_suffix = get_domain(addr.addr4);
1.1 misho 1107: }
1108: else if (inet_pton(AF_INET6, token, &addr) > 0)
1109: {
1110: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
1111: addrlen = IN6ADDRSZ;
1.1.1.4 ! misho 1112: domain_suffix = get_domain6(&addr.addr6);
1.1 misho 1113: }
1114: else
1115: {
1116: my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
1117: while (atnl == 0)
1118: atnl = gettok(f, token);
1.1.1.4 ! misho 1119: lineno += atnl;
1.1 misho 1120: continue;
1121: }
1122:
1123: addr_count++;
1124:
1125: /* rehash every 1000 names. */
1.1.1.3 misho 1126: if (rhash && ((name_count - cache_size) > 1000))
1.1 misho 1127: {
1128: rehash(name_count);
1129: cache_size = name_count;
1130: }
1131:
1132: while (atnl == 0)
1133: {
1134: struct crec *cache;
1135: int fqdn, nomem;
1136: char *canon;
1137:
1.1.1.4 ! misho 1138: if ((atnl = gettok(f, token)) == -1)
1.1 misho 1139: break;
1140:
1141: fqdn = !!strchr(token, '.');
1142:
1143: if ((canon = canonicalise(token, &nomem)))
1144: {
1145: /* If set, add a version of the name with a default domain appended */
1146: if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
1.1.1.4 ! misho 1147: (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
1.1 misho 1148: {
1149: strcpy(cache->name.sname, canon);
1150: strcat(cache->name.sname, ".");
1151: strcat(cache->name.sname, domain_suffix);
1152: cache->flags = flags;
1.1.1.3 misho 1153: cache->ttd = daemon->local_ttl;
1.1 misho 1154: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
1155: name_count++;
1156: }
1.1.1.4 ! misho 1157: if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
1.1 misho 1158: {
1159: strcpy(cache->name.sname, canon);
1160: cache->flags = flags;
1.1.1.3 misho 1161: cache->ttd = daemon->local_ttl;
1.1 misho 1162: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
1163: name_count++;
1164: }
1165: free(canon);
1166:
1167: }
1168: else if (!nomem)
1169: my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1170: }
1.1.1.4 ! misho 1171:
! 1172: lineno += atnl;
1.1 misho 1173: }
1174:
1175: fclose(f);
1.1.1.3 misho 1176:
1177: if (rhash)
1178: rehash(name_count);
1.1 misho 1179:
1180: my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1181:
1182: return name_count;
1183: }
1184:
1185: void cache_reload(void)
1186: {
1187: struct crec *cache, **up, *tmp;
1188: int revhashsz, i, total_size = daemon->cachesize;
1189: struct hostsfile *ah;
1190: struct host_record *hr;
1191: struct name_list *nl;
1.1.1.2 misho 1192: struct cname *a;
1.1.1.4 ! misho 1193: struct crec lrec;
! 1194: struct mx_srv_record *mx;
! 1195: struct txt_record *txt;
1.1.1.2 misho 1196: struct interface_name *intr;
1.1.1.4 ! misho 1197: struct ptr_record *ptr;
! 1198: struct naptr *naptr;
1.1.1.2 misho 1199: #ifdef HAVE_DNSSEC
1200: struct ds_config *ds;
1201: #endif
1.1 misho 1202:
1.1.1.4 ! misho 1203: daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
! 1204: daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
1.1 misho 1205:
1206: for (i=0; i<hash_size; i++)
1207: for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1208: {
1.1.1.2 misho 1209: cache_blockdata_free(cache);
1.1.1.4 ! misho 1210:
1.1 misho 1211: tmp = cache->hash_next;
1.1.1.2 misho 1212: if (cache->flags & (F_HOSTS | F_CONFIG))
1.1 misho 1213: {
1214: *up = cache->hash_next;
1215: free(cache);
1216: }
1217: else if (!(cache->flags & F_DHCP))
1218: {
1219: *up = cache->hash_next;
1220: if (cache->flags & F_BIGNAME)
1221: {
1222: cache->name.bname->next = big_free;
1223: big_free = cache->name.bname;
1224: }
1225: cache->flags = 0;
1226: }
1227: else
1228: up = &cache->hash_next;
1229: }
1230:
1.1.1.4 ! misho 1231: /* Add locally-configured CNAMEs to the cache */
1.1.1.2 misho 1232: for (a = daemon->cnames; a; a = a->next)
1.1.1.4 ! misho 1233: if (a->alias[1] != '*' &&
! 1234: ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
! 1235: {
! 1236: cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
! 1237: cache->ttd = a->ttl;
! 1238: cache->name.namep = a->alias;
! 1239: cache->addr.cname.target.name = a->target;
! 1240: cache->addr.cname.is_name_ptr = 1;
! 1241: cache->uid = UID_NONE;
! 1242: cache_hash(cache);
! 1243: make_non_terminals(cache);
! 1244: }
! 1245:
1.1.1.2 misho 1246: #ifdef HAVE_DNSSEC
1247: for (ds = daemon->ds; ds; ds = ds->next)
1.1.1.4 ! misho 1248: if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
1.1.1.2 misho 1249: (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
1250: {
1251: cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1.1.1.3 misho 1252: cache->ttd = daemon->local_ttl;
1.1.1.2 misho 1253: cache->name.namep = ds->name;
1254: cache->addr.ds.keylen = ds->digestlen;
1255: cache->addr.ds.algo = ds->algo;
1256: cache->addr.ds.keytag = ds->keytag;
1257: cache->addr.ds.digest = ds->digest_type;
1258: cache->uid = ds->class;
1259: cache_hash(cache);
1.1.1.4 ! misho 1260: make_non_terminals(cache);
1.1.1.2 misho 1261: }
1262: #endif
1263:
1.1 misho 1264: /* borrow the packet buffer for a temporary by-address hash */
1265: memset(daemon->packet, 0, daemon->packet_buff_sz);
1266: revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1267: /* we overwrote the buffer... */
1268: daemon->srv_save = NULL;
1269:
1270: /* Do host_records in config. */
1271: for (hr = daemon->host_records; hr; hr = hr->next)
1272: for (nl = hr->names; nl; nl = nl->next)
1273: {
1.1.1.4 ! misho 1274: if ((hr->flags & HR_4) &&
! 1275: (cache = whine_malloc(SIZEOF_POINTER_CREC)))
1.1 misho 1276: {
1277: cache->name.namep = nl->name;
1.1.1.3 misho 1278: cache->ttd = hr->ttl;
1.1 misho 1279: cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
1.1.1.4 ! misho 1280: add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1.1 misho 1281: }
1.1.1.4 ! misho 1282:
! 1283: if ((hr->flags & HR_6) &&
! 1284: (cache = whine_malloc(SIZEOF_POINTER_CREC)))
1.1 misho 1285: {
1286: cache->name.namep = nl->name;
1.1.1.3 misho 1287: cache->ttd = hr->ttl;
1.1 misho 1288: cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
1.1.1.4 ! misho 1289: add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1.1 misho 1290: }
1291: }
1292:
1293: if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
1294: {
1295: if (daemon->cachesize > 0)
1296: my_syslog(LOG_INFO, _("cleared cache"));
1297: }
1.1.1.3 misho 1298: else
1299: {
1300: if (!option_bool(OPT_NO_HOSTS))
1301: total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1302:
1303: daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1304: for (ah = daemon->addn_hosts; ah; ah = ah->next)
1305: if (!(ah->flags & AH_INACTIVE))
1306: total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1307: }
1.1.1.4 ! misho 1308:
! 1309: /* Make non-terminal records for all locally-define RRs */
! 1310: lrec.flags = F_FORWARD | F_CONFIG | F_NAMEP | F_IMMORTAL;
! 1311:
! 1312: for (txt = daemon->txt; txt; txt = txt->next)
! 1313: {
! 1314: lrec.name.namep = txt->name;
! 1315: make_non_terminals(&lrec);
! 1316: }
! 1317:
! 1318: for (naptr = daemon->naptr; naptr; naptr = naptr->next)
! 1319: {
! 1320: lrec.name.namep = naptr->name;
! 1321: make_non_terminals(&lrec);
! 1322: }
1.1.1.3 misho 1323:
1.1.1.4 ! misho 1324: for (mx = daemon->mxnames; mx; mx = mx->next)
! 1325: {
! 1326: lrec.name.namep = mx->name;
! 1327: make_non_terminals(&lrec);
! 1328: }
! 1329:
! 1330: for (intr = daemon->int_names; intr; intr = intr->next)
! 1331: {
! 1332: lrec.name.namep = intr->name;
! 1333: make_non_terminals(&lrec);
! 1334: }
! 1335:
! 1336: for (ptr = daemon->ptr; ptr; ptr = ptr->next)
! 1337: {
! 1338: lrec.name.namep = ptr->name;
! 1339: make_non_terminals(&lrec);
! 1340: }
! 1341:
1.1.1.3 misho 1342: #ifdef HAVE_INOTIFY
1343: set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1344: #endif
1345:
1.1 misho 1346: }
1347:
1348: #ifdef HAVE_DHCP
1349: struct in_addr a_record_from_hosts(char *name, time_t now)
1350: {
1351: struct crec *crecp = NULL;
1352: struct in_addr ret;
1353:
1354: while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1355: if (crecp->flags & F_HOSTS)
1.1.1.4 ! misho 1356: return crecp->addr.addr4;
1.1 misho 1357:
1358: my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1359:
1360: ret.s_addr = 0;
1361: return ret;
1362: }
1363:
1364: void cache_unhash_dhcp(void)
1365: {
1366: struct crec *cache, **up;
1367: int i;
1368:
1369: for (i=0; i<hash_size; i++)
1370: for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1371: if (cache->flags & F_DHCP)
1372: {
1373: *up = cache->hash_next;
1374: cache->next = dhcp_spare;
1375: dhcp_spare = cache;
1376: }
1377: else
1378: up = &cache->hash_next;
1379: }
1380:
1381: void cache_add_dhcp_entry(char *host_name, int prot,
1.1.1.4 ! misho 1382: union all_addr *host_address, time_t ttd)
1.1 misho 1383: {
1384: struct crec *crec = NULL, *fail_crec = NULL;
1.1.1.4 ! misho 1385: unsigned int flags = F_IPV4;
1.1 misho 1386: int in_hosts = 0;
1387: size_t addrlen = sizeof(struct in_addr);
1388:
1389: if (prot == AF_INET6)
1390: {
1391: flags = F_IPV6;
1392: addrlen = sizeof(struct in6_addr);
1393: }
1394:
1395: inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1396:
1397: while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
1398: {
1399: /* check all addresses associated with name */
1.1.1.2 misho 1400: if (crec->flags & (F_HOSTS | F_CONFIG))
1.1 misho 1401: {
1402: if (crec->flags & F_CNAME)
1403: my_syslog(MS_DHCP | LOG_WARNING,
1404: _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1405: host_name, daemon->addrbuff);
1.1.1.4 ! misho 1406: else if (memcmp(&crec->addr, host_address, addrlen) == 0)
1.1 misho 1407: in_hosts = 1;
1408: else
1409: fail_crec = crec;
1410: }
1411: else if (!(crec->flags & F_DHCP))
1412: {
1.1.1.4 ! misho 1413: cache_scan_free(host_name, NULL, C_IN, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
1.1 misho 1414: /* scan_free deletes all addresses associated with name */
1415: break;
1416: }
1417: }
1418:
1419: /* if in hosts, don't need DHCP record */
1420: if (in_hosts)
1421: return;
1422:
1423: /* Name in hosts, address doesn't match */
1424: if (fail_crec)
1425: {
1.1.1.4 ! misho 1426: inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME);
1.1 misho 1427: my_syslog(MS_DHCP | LOG_WARNING,
1428: _("not giving name %s to the DHCP lease of %s because "
1429: "the name exists in %s with address %s"),
1430: host_name, daemon->addrbuff,
1431: record_source(fail_crec->uid), daemon->namebuff);
1432: return;
1433: }
1434:
1.1.1.4 ! misho 1435: if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags)))
1.1 misho 1436: {
1437: if (crec->flags & F_NEG)
1438: {
1439: flags |= F_REVERSE;
1.1.1.4 ! misho 1440: cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
1.1 misho 1441: }
1442: }
1443: else
1444: flags |= F_REVERSE;
1445:
1446: if ((crec = dhcp_spare))
1447: dhcp_spare = dhcp_spare->next;
1448: else /* need new one */
1.1.1.4 ! misho 1449: crec = whine_malloc(SIZEOF_POINTER_CREC);
1.1 misho 1450:
1451: if (crec) /* malloc may fail */
1452: {
1453: crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
1454: if (ttd == 0)
1455: crec->flags |= F_IMMORTAL;
1456: else
1457: crec->ttd = ttd;
1.1.1.4 ! misho 1458: crec->addr = *host_address;
1.1 misho 1459: crec->name.namep = host_name;
1.1.1.4 ! misho 1460: crec->uid = UID_NONE;
1.1 misho 1461: cache_hash(crec);
1.1.1.4 ! misho 1462: make_non_terminals(crec);
1.1 misho 1463: }
1464: }
1465: #endif
1466:
1.1.1.4 ! misho 1467: /* Called when we put a local or DHCP name into the cache.
! 1468: Creates empty cache entries for subnames (ie,
! 1469: for three.two.one, for two.one and one), without
! 1470: F_IPV4 or F_IPV6 or F_CNAME set. These convert
! 1471: NXDOMAIN answers to NoData ones. */
! 1472: static void make_non_terminals(struct crec *source)
! 1473: {
! 1474: char *name = cache_get_name(source);
! 1475: struct crec *crecp, *tmp, **up;
! 1476: int type = F_HOSTS | F_CONFIG;
! 1477: #ifdef HAVE_DHCP
! 1478: if (source->flags & F_DHCP)
! 1479: type = F_DHCP;
! 1480: #endif
! 1481:
! 1482: /* First delete any empty entries for our new real name. Note that
! 1483: we only delete empty entries deriving from DHCP for a new DHCP-derived
! 1484: entry and vice-versa for HOSTS and CONFIG. This ensures that
! 1485: non-terminals from DHCP go when we reload DHCP and
! 1486: for HOSTS/CONFIG when we re-read. */
! 1487: for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
! 1488: {
! 1489: tmp = crecp->hash_next;
! 1490:
! 1491: if (!is_outdated_cname_pointer(crecp) &&
! 1492: (crecp->flags & F_FORWARD) &&
! 1493: (crecp->flags & type) &&
! 1494: !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS)) &&
! 1495: hostname_isequal(name, cache_get_name(crecp)))
! 1496: {
! 1497: *up = crecp->hash_next;
! 1498: #ifdef HAVE_DHCP
! 1499: if (type & F_DHCP)
! 1500: {
! 1501: crecp->next = dhcp_spare;
! 1502: dhcp_spare = crecp;
! 1503: }
! 1504: else
! 1505: #endif
! 1506: free(crecp);
! 1507: break;
! 1508: }
! 1509: else
! 1510: up = &crecp->hash_next;
! 1511: }
! 1512:
! 1513: while ((name = strchr(name, '.')))
! 1514: {
! 1515: name++;
! 1516:
! 1517: /* Look for one existing, don't need another */
! 1518: for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
! 1519: if (!is_outdated_cname_pointer(crecp) &&
! 1520: (crecp->flags & F_FORWARD) &&
! 1521: (crecp->flags & type) &&
! 1522: hostname_isequal(name, cache_get_name(crecp)))
! 1523: break;
! 1524:
! 1525: if (crecp)
! 1526: {
! 1527: /* If the new name expires later, transfer that time to
! 1528: empty non-terminal entry. */
! 1529: if (!(crecp->flags & F_IMMORTAL))
! 1530: {
! 1531: if (source->flags & F_IMMORTAL)
! 1532: crecp->flags |= F_IMMORTAL;
! 1533: else if (difftime(crecp->ttd, source->ttd) < 0)
! 1534: crecp->ttd = source->ttd;
! 1535: }
! 1536: continue;
! 1537: }
! 1538:
! 1539: #ifdef HAVE_DHCP
! 1540: if ((source->flags & F_DHCP) && dhcp_spare)
! 1541: {
! 1542: crecp = dhcp_spare;
! 1543: dhcp_spare = dhcp_spare->next;
! 1544: }
! 1545: else
! 1546: #endif
! 1547: crecp = whine_malloc(SIZEOF_POINTER_CREC);
! 1548:
! 1549: if (crecp)
! 1550: {
! 1551: crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
! 1552: crecp->ttd = source->ttd;
! 1553: crecp->name.namep = name;
! 1554:
! 1555: cache_hash(crecp);
! 1556: }
! 1557: }
! 1558: }
! 1559:
! 1560: #ifndef NO_ID
1.1.1.2 misho 1561: int cache_make_stat(struct txt_record *t)
1562: {
1563: static char *buff = NULL;
1564: static int bufflen = 60;
1565: int len;
1566: struct server *serv, *serv1;
1567: char *p;
1568:
1569: if (!buff && !(buff = whine_malloc(60)))
1570: return 0;
1571:
1572: p = buff;
1573:
1574: switch (t->stat)
1575: {
1576: case TXT_STAT_CACHESIZE:
1577: sprintf(buff+1, "%d", daemon->cachesize);
1578: break;
1579:
1580: case TXT_STAT_INSERTS:
1.1.1.4 ! misho 1581: sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
1.1.1.2 misho 1582: break;
1583:
1584: case TXT_STAT_EVICTIONS:
1.1.1.4 ! misho 1585: sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
1.1.1.2 misho 1586: break;
1587:
1588: case TXT_STAT_MISSES:
1.1.1.4 ! misho 1589: sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
1.1.1.2 misho 1590: break;
1591:
1592: case TXT_STAT_HITS:
1.1.1.4 ! misho 1593: sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
1.1.1.2 misho 1594: break;
1595:
1596: #ifdef HAVE_AUTH
1597: case TXT_STAT_AUTH:
1.1.1.4 ! misho 1598: sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
1.1.1.2 misho 1599: break;
1600: #endif
1601:
1602: case TXT_STAT_SERVERS:
1603: /* sum counts from different records for same server */
1604: for (serv = daemon->servers; serv; serv = serv->next)
1605: serv->flags &= ~SERV_COUNTED;
1606:
1607: for (serv = daemon->servers; serv; serv = serv->next)
1608: if (!(serv->flags &
1609: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1610: {
1611: char *new, *lenp;
1612: int port, newlen, bytes_avail, bytes_needed;
1613: unsigned int queries = 0, failed_queries = 0;
1614: for (serv1 = serv; serv1; serv1 = serv1->next)
1615: if (!(serv1->flags &
1616: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1617: sockaddr_isequal(&serv->addr, &serv1->addr))
1618: {
1619: serv1->flags |= SERV_COUNTED;
1620: queries += serv1->queries;
1621: failed_queries += serv1->failed_queries;
1622: }
1623: port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1624: lenp = p++; /* length */
1.1.1.3 misho 1625: bytes_avail = bufflen - (p - buff );
1.1.1.2 misho 1626: bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1627: if (bytes_needed >= bytes_avail)
1628: {
1629: /* expand buffer if necessary */
1630: newlen = bytes_needed + 1 + bufflen - bytes_avail;
1631: if (!(new = whine_malloc(newlen)))
1632: return 0;
1633: memcpy(new, buff, bufflen);
1634: free(buff);
1635: p = new + (p - buff);
1636: lenp = p - 1;
1637: buff = new;
1638: bufflen = newlen;
1.1.1.3 misho 1639: bytes_avail = bufflen - (p - buff );
1.1.1.2 misho 1640: bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1641: }
1642: *lenp = bytes_needed;
1643: p += bytes_needed;
1644: }
1645: t->txt = (unsigned char *)buff;
1646: t->len = p - buff;
1647: return 1;
1648: }
1649:
1650: len = strlen(buff+1);
1651: t->txt = (unsigned char *)buff;
1652: t->len = len + 1;
1653: *buff = len;
1654: return 1;
1655: }
1.1.1.4 ! misho 1656: #endif
1.1 misho 1657:
1.1.1.3 misho 1658: /* There can be names in the cache containing control chars, don't
1659: mess up logging or open security holes. */
1660: static char *sanitise(char *name)
1661: {
1662: unsigned char *r;
1663: if (name)
1664: for (r = (unsigned char *)name; *r; r++)
1665: if (!isprint((int)*r))
1666: return "<name unprintable>";
1667:
1668: return name;
1669: }
1670:
1671:
1.1 misho 1672: void dump_cache(time_t now)
1673: {
1674: struct server *serv, *serv1;
1675:
1676: my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1677: my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1.1.1.4 ! misho 1678: daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
1.1 misho 1679: my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1.1.1.4 ! misho 1680: daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
1.1.1.2 misho 1681: #ifdef HAVE_AUTH
1.1.1.4 ! misho 1682: my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
1.1.1.2 misho 1683: #endif
1.1.1.4 ! misho 1684:
1.1.1.2 misho 1685: blockdata_report();
1.1 misho 1686:
1687: /* sum counts from different records for same server */
1688: for (serv = daemon->servers; serv; serv = serv->next)
1689: serv->flags &= ~SERV_COUNTED;
1690:
1691: for (serv = daemon->servers; serv; serv = serv->next)
1692: if (!(serv->flags &
1693: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1694: {
1695: int port;
1696: unsigned int queries = 0, failed_queries = 0;
1697: for (serv1 = serv; serv1; serv1 = serv1->next)
1698: if (!(serv1->flags &
1699: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1700: sockaddr_isequal(&serv->addr, &serv1->addr))
1701: {
1702: serv1->flags |= SERV_COUNTED;
1703: queries += serv1->queries;
1704: failed_queries += serv1->failed_queries;
1705: }
1706: port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1707: my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
1708: }
1709:
1710: if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
1711: {
1712: struct crec *cache ;
1713: int i;
1.1.1.2 misho 1714: my_syslog(LOG_INFO, "Host Address Flags Expires");
1.1 misho 1715:
1716: for (i=0; i<hash_size; i++)
1717: for (cache = hash_table[i]; cache; cache = cache->hash_next)
1718: {
1.1.1.4 ! misho 1719: char *t = " ";
1.1.1.2 misho 1720: char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1721: *a = 0;
1722: if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
1723: n = "<Root>";
1.1.1.3 misho 1724: p += sprintf(p, "%-30.30s ", sanitise(n));
1.1.1.2 misho 1725: if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
1.1.1.3 misho 1726: a = sanitise(cache_get_cname_target(cache));
1.1.1.4 ! misho 1727: else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
! 1728: {
! 1729: int targetlen = cache->addr.srv.targetlen;
! 1730: ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
! 1731: cache->addr.srv.weight, cache->addr.srv.srvport);
! 1732:
! 1733: if (targetlen > (40 - len))
! 1734: targetlen = 40 - len;
! 1735: blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
! 1736: a[len + targetlen] = 0;
! 1737: }
1.1 misho 1738: #ifdef HAVE_DNSSEC
1739: else if (cache->flags & F_DS)
1740: {
1.1.1.3 misho 1741: if (!(cache->flags & F_NEG))
1.1.1.2 misho 1742: sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1743: cache->addr.ds.algo, cache->addr.ds.digest);
1.1 misho 1744: }
1.1.1.2 misho 1745: else if (cache->flags & F_DNSKEY)
1746: sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1747: cache->addr.key.algo, cache->addr.key.flags);
1.1 misho 1748: #endif
1.1.1.2 misho 1749: else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
1.1 misho 1750: {
1751: a = daemon->addrbuff;
1752: if (cache->flags & F_IPV4)
1.1.1.4 ! misho 1753: inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN);
1.1 misho 1754: else if (cache->flags & F_IPV6)
1.1.1.4 ! misho 1755: inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN);
1.1 misho 1756: }
1757:
1.1.1.2 misho 1758: if (cache->flags & F_IPV4)
1759: t = "4";
1760: else if (cache->flags & F_IPV6)
1761: t = "6";
1762: else if (cache->flags & F_CNAME)
1763: t = "C";
1.1.1.4 ! misho 1764: else if (cache->flags & F_SRV)
! 1765: t = "V";
1.1.1.2 misho 1766: #ifdef HAVE_DNSSEC
1767: else if (cache->flags & F_DS)
1768: t = "S";
1769: else if (cache->flags & F_DNSKEY)
1770: t = "K";
1771: #endif
1.1.1.3 misho 1772: p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
1.1 misho 1773: cache->flags & F_FORWARD ? "F" : " ",
1774: cache->flags & F_REVERSE ? "R" : " ",
1775: cache->flags & F_IMMORTAL ? "I" : " ",
1776: cache->flags & F_DHCP ? "D" : " ",
1777: cache->flags & F_NEG ? "N" : " ",
1778: cache->flags & F_NXDOMAIN ? "X" : " ",
1779: cache->flags & F_HOSTS ? "H" : " ",
1780: cache->flags & F_DNSSECOK ? "V" : " ");
1781: #ifdef HAVE_BROKEN_RTC
1782: p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1783: #else
1784: p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1785: /* ctime includes trailing \n - eat it */
1786: *(p-1) = 0;
1787: #endif
1.1.1.4 ! misho 1788: my_syslog(LOG_INFO, "%s", daemon->namebuff);
1.1 misho 1789: }
1790: }
1791: }
1792:
1.1.1.2 misho 1793: char *record_source(unsigned int index)
1.1 misho 1794: {
1795: struct hostsfile *ah;
1796:
1.1.1.2 misho 1797: if (index == SRC_CONFIG)
1798: return "config";
1799: else if (index == SRC_HOSTS)
1.1 misho 1800: return HOSTSFILE;
1801:
1802: for (ah = daemon->addn_hosts; ah; ah = ah->next)
1803: if (ah->index == index)
1804: return ah->fname;
1.1.1.3 misho 1805:
1806: #ifdef HAVE_INOTIFY
1807: for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1808: if (ah->index == index)
1809: return ah->fname;
1810: #endif
1811:
1.1 misho 1812: return "<unknown>";
1813: }
1814:
1.1.1.2 misho 1815: char *querystr(char *desc, unsigned short type)
1.1 misho 1816: {
1817: unsigned int i;
1.1.1.2 misho 1818: int len = 10; /* strlen("type=xxxxx") */
1819: const char *types = NULL;
1820: static char *buff = NULL;
1821: static int bufflen = 0;
1822:
1.1 misho 1823: for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1824: if (typestr[i].type == type)
1.1.1.2 misho 1825: {
1826: types = typestr[i].name;
1827: len = strlen(types);
1828: break;
1829: }
1830:
1.1.1.4 ! misho 1831: if (desc)
! 1832: {
! 1833: len += 2; /* braces */
! 1834: len += strlen(desc);
! 1835: }
! 1836: len++; /* terminator */
! 1837:
1.1.1.2 misho 1838: if (!buff || bufflen < len)
1839: {
1840: if (buff)
1841: free(buff);
1842: else if (len < 20)
1843: len = 20;
1844:
1845: buff = whine_malloc(len);
1846: bufflen = len;
1847: }
1848:
1849: if (buff)
1850: {
1.1.1.4 ! misho 1851: if (desc)
! 1852: {
! 1853: if (types)
! 1854: sprintf(buff, "%s[%s]", desc, types);
! 1855: else
! 1856: sprintf(buff, "%s[type=%d]", desc, type);
! 1857: }
1.1.1.2 misho 1858: else
1.1.1.4 ! misho 1859: {
! 1860: if (types)
! 1861: sprintf(buff, "<%s>", types);
! 1862: else
! 1863: sprintf(buff, "type=%d", type);
! 1864: }
1.1.1.2 misho 1865: }
1.1.1.4 ! misho 1866:
1.1.1.2 misho 1867: return buff ? buff : "";
1.1 misho 1868: }
1869:
1.1.1.4 ! misho 1870: void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
1.1 misho 1871: {
1872: char *source, *dest = daemon->addrbuff;
1873: char *verb = "is";
1874:
1875: if (!option_bool(OPT_LOG))
1876: return;
1877:
1.1.1.3 misho 1878: name = sanitise(name);
1879:
1.1 misho 1880: if (addr)
1881: {
1.1.1.2 misho 1882: if (flags & F_KEYTAG)
1.1.1.4 ! misho 1883: sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
! 1884: else if (flags & F_RCODE)
1.1.1.2 misho 1885: {
1.1.1.4 ! misho 1886: unsigned int rcode = addr->log.rcode;
! 1887:
! 1888: if (rcode == SERVFAIL)
! 1889: dest = "SERVFAIL";
! 1890: else if (rcode == REFUSED)
! 1891: dest = "REFUSED";
! 1892: else if (rcode == NOTIMP)
! 1893: dest = "not implemented";
! 1894: else
! 1895: sprintf(daemon->addrbuff, "%u", rcode);
1.1.1.2 misho 1896: }
1.1.1.4 ! misho 1897: else
! 1898: inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
! 1899: addr, daemon->addrbuff, ADDRSTRLEN);
! 1900:
1.1 misho 1901: }
1.1.1.2 misho 1902: else
1903: dest = arg;
1.1 misho 1904:
1905: if (flags & F_REVERSE)
1906: {
1907: dest = name;
1908: name = daemon->addrbuff;
1909: }
1910:
1911: if (flags & F_NEG)
1912: {
1913: if (flags & F_NXDOMAIN)
1.1.1.2 misho 1914: dest = "NXDOMAIN";
1.1 misho 1915: else
1916: {
1917: if (flags & F_IPV4)
1918: dest = "NODATA-IPv4";
1919: else if (flags & F_IPV6)
1920: dest = "NODATA-IPv6";
1921: else
1922: dest = "NODATA";
1923: }
1924: }
1925: else if (flags & F_CNAME)
1926: dest = "<CNAME>";
1.1.1.4 ! misho 1927: else if (flags & F_SRV)
! 1928: dest = "<SRV>";
1.1 misho 1929: else if (flags & F_RRNAME)
1930: dest = arg;
1931:
1932: if (flags & F_CONFIG)
1933: source = "config";
1934: else if (flags & F_DHCP)
1935: source = "DHCP";
1936: else if (flags & F_HOSTS)
1937: source = arg;
1938: else if (flags & F_UPSTREAM)
1939: source = "reply";
1.1.1.2 misho 1940: else if (flags & F_SECSTAT)
1941: source = "validation";
1.1 misho 1942: else if (flags & F_AUTH)
1943: source = "auth";
1944: else if (flags & F_SERVER)
1945: {
1946: source = "forwarded";
1947: verb = "to";
1948: }
1949: else if (flags & F_QUERY)
1950: {
1951: source = arg;
1952: verb = "from";
1953: }
1.1.1.2 misho 1954: else if (flags & F_DNSSEC)
1955: {
1956: source = arg;
1957: verb = "to";
1958: }
1959: else if (flags & F_IPSET)
1960: {
1961: source = "ipset add";
1962: dest = name;
1963: name = arg;
1964: verb = daemon->addrbuff;
1965: }
1.1 misho 1966: else
1967: source = "cached";
1968:
1969: if (strlen(name) == 0)
1970: name = ".";
1971:
1.1.1.3 misho 1972: if (option_bool(OPT_EXTRALOG))
1973: {
1974: int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
1975: if (flags & F_NOEXTRA)
1976: my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
1977: else
1978: my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
1979: }
1980: else
1981: my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
1.1 misho 1982: }
1983:
1.1.1.2 misho 1984:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>