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