Annotation of embedaddon/dnsmasq/src/cache.c, revision 1.1
1.1 ! misho 1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
! 2:
! 3: This program is free software; you can redistribute it and/or modify
! 4: it under the terms of the GNU General Public License as published by
! 5: the Free Software Foundation; version 2 dated June, 1991, or
! 6: (at your option) version 3 dated 29 June, 2007.
! 7:
! 8: This program is distributed in the hope that it will be useful,
! 9: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 11: GNU General Public License for more details.
! 12:
! 13: You should have received a copy of the GNU General Public License
! 14: along with this program. If not, see <http://www.gnu.org/licenses/>.
! 15: */
! 16:
! 17: #include "dnsmasq.h"
! 18:
! 19: static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
! 20: #ifdef HAVE_DHCP
! 21: static struct crec *dhcp_spare = NULL;
! 22: #endif
! 23: static struct crec *new_chain = NULL;
! 24: static int cache_inserted = 0, cache_live_freed = 0, insert_error;
! 25: static union bigname *big_free = NULL;
! 26: static int bignames_left, hash_size;
! 27: static int uid = 0;
! 28: #ifdef HAVE_DNSSEC
! 29: static struct keydata *keyblock_free = NULL;
! 30: #endif
! 31:
! 32: /* type->string mapping: this is also used by the name-hash function as a mixing table. */
! 33: static const struct {
! 34: unsigned int type;
! 35: const char * const name;
! 36: } typestr[] = {
! 37: { 1, "A" },
! 38: { 2, "NS" },
! 39: { 5, "CNAME" },
! 40: { 6, "SOA" },
! 41: { 10, "NULL" },
! 42: { 11, "WKS" },
! 43: { 12, "PTR" },
! 44: { 13, "HINFO" },
! 45: { 15, "MX" },
! 46: { 16, "TXT" },
! 47: { 22, "NSAP" },
! 48: { 23, "NSAP_PTR" },
! 49: { 24, "SIG" },
! 50: { 25, "KEY" },
! 51: { 28, "AAAA" },
! 52: { 33, "SRV" },
! 53: { 35, "NAPTR" },
! 54: { 36, "KX" },
! 55: { 37, "CERT" },
! 56: { 38, "A6" },
! 57: { 39, "DNAME" },
! 58: { 41, "OPT" },
! 59: { 48, "DNSKEY" },
! 60: { 249, "TKEY" },
! 61: { 250, "TSIG" },
! 62: { 251, "IXFR" },
! 63: { 252, "AXFR" },
! 64: { 253, "MAILB" },
! 65: { 254, "MAILA" },
! 66: { 255, "ANY" }
! 67: };
! 68:
! 69: static void cache_free(struct crec *crecp);
! 70: static void cache_unlink(struct crec *crecp);
! 71: static void cache_link(struct crec *crecp);
! 72: static void rehash(int size);
! 73: static void cache_hash(struct crec *crecp);
! 74:
! 75: void cache_init(void)
! 76: {
! 77: struct crec *crecp;
! 78: int i;
! 79:
! 80: bignames_left = daemon->cachesize/10;
! 81:
! 82: if (daemon->cachesize > 0)
! 83: {
! 84: crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
! 85:
! 86: for (i=0; i < daemon->cachesize; i++, crecp++)
! 87: {
! 88: cache_link(crecp);
! 89: crecp->flags = 0;
! 90: crecp->uid = uid++;
! 91: }
! 92: }
! 93:
! 94: /* create initial hash table*/
! 95: rehash(daemon->cachesize);
! 96: }
! 97:
! 98: /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
! 99: but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
! 100: will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
! 101: expand the table. */
! 102: static void rehash(int size)
! 103: {
! 104: struct crec **new, **old, *p, *tmp;
! 105: int i, new_size, old_size;
! 106:
! 107: /* hash_size is a power of two. */
! 108: for (new_size = 64; new_size < size/10; new_size = new_size << 1);
! 109:
! 110: /* must succeed in getting first instance, failure later is non-fatal */
! 111: if (!hash_table)
! 112: new = safe_malloc(new_size * sizeof(struct crec *));
! 113: else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
! 114: return;
! 115:
! 116: for(i = 0; i < new_size; i++)
! 117: new[i] = NULL;
! 118:
! 119: old = hash_table;
! 120: old_size = hash_size;
! 121: hash_table = new;
! 122: hash_size = new_size;
! 123:
! 124: if (old)
! 125: {
! 126: for (i = 0; i < old_size; i++)
! 127: for (p = old[i]; p ; p = tmp)
! 128: {
! 129: tmp = p->hash_next;
! 130: cache_hash(p);
! 131: }
! 132: free(old);
! 133: }
! 134: }
! 135:
! 136: static struct crec **hash_bucket(char *name)
! 137: {
! 138: unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
! 139: const unsigned char *mix_tab = (const unsigned char*)typestr;
! 140:
! 141: while((c = (unsigned char) *name++))
! 142: {
! 143: /* don't use tolower and friends here - they may be messed up by LOCALE */
! 144: if (c >= 'A' && c <= 'Z')
! 145: c += 'a' - 'A';
! 146: val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
! 147: }
! 148:
! 149: /* hash_size is a power of two */
! 150: return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
! 151: }
! 152:
! 153: static void cache_hash(struct crec *crecp)
! 154: {
! 155: /* maintain an invariant that all entries with F_REVERSE set
! 156: are at the start of the hash-chain and all non-reverse
! 157: immortal entries are at the end of the hash-chain.
! 158: This allows reverse searches and garbage collection to be optimised */
! 159:
! 160: struct crec **up = hash_bucket(cache_get_name(crecp));
! 161:
! 162: if (!(crecp->flags & F_REVERSE))
! 163: {
! 164: while (*up && ((*up)->flags & F_REVERSE))
! 165: up = &((*up)->hash_next);
! 166:
! 167: if (crecp->flags & F_IMMORTAL)
! 168: while (*up && !((*up)->flags & F_IMMORTAL))
! 169: up = &((*up)->hash_next);
! 170: }
! 171: crecp->hash_next = *up;
! 172: *up = crecp;
! 173: }
! 174:
! 175: static void cache_free(struct crec *crecp)
! 176: {
! 177: crecp->flags &= ~F_FORWARD;
! 178: crecp->flags &= ~F_REVERSE;
! 179: crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
! 180:
! 181: if (cache_tail)
! 182: cache_tail->next = crecp;
! 183: else
! 184: cache_head = crecp;
! 185: crecp->prev = cache_tail;
! 186: crecp->next = NULL;
! 187: cache_tail = crecp;
! 188:
! 189: /* retrieve big name for further use. */
! 190: if (crecp->flags & F_BIGNAME)
! 191: {
! 192: crecp->name.bname->next = big_free;
! 193: big_free = crecp->name.bname;
! 194: crecp->flags &= ~F_BIGNAME;
! 195: }
! 196: #ifdef HAVE_DNSSEC
! 197: else if (crecp->flags & (F_DNSKEY | F_DS))
! 198: keydata_free(crecp->addr.key.keydata);
! 199: #endif
! 200: }
! 201:
! 202: /* insert a new cache entry at the head of the list (youngest entry) */
! 203: static void cache_link(struct crec *crecp)
! 204: {
! 205: if (cache_head) /* check needed for init code */
! 206: cache_head->prev = crecp;
! 207: crecp->next = cache_head;
! 208: crecp->prev = NULL;
! 209: cache_head = crecp;
! 210: if (!cache_tail)
! 211: cache_tail = crecp;
! 212: }
! 213:
! 214: /* remove an arbitrary cache entry for promotion */
! 215: static void cache_unlink (struct crec *crecp)
! 216: {
! 217: if (crecp->prev)
! 218: crecp->prev->next = crecp->next;
! 219: else
! 220: cache_head = crecp->next;
! 221:
! 222: if (crecp->next)
! 223: crecp->next->prev = crecp->prev;
! 224: else
! 225: cache_tail = crecp->prev;
! 226: }
! 227:
! 228: char *cache_get_name(struct crec *crecp)
! 229: {
! 230: if (crecp->flags & F_BIGNAME)
! 231: return crecp->name.bname->name;
! 232: else if (crecp->flags & F_NAMEP)
! 233: return crecp->name.namep;
! 234:
! 235: return crecp->name.sname;
! 236: }
! 237:
! 238: struct crec *cache_enumerate(int init)
! 239: {
! 240: static int bucket;
! 241: static struct crec *cache;
! 242:
! 243: if (init)
! 244: {
! 245: bucket = 0;
! 246: cache = NULL;
! 247: }
! 248: else if (cache && cache->hash_next)
! 249: cache = cache->hash_next;
! 250: else
! 251: {
! 252: cache = NULL;
! 253: while (bucket < hash_size)
! 254: if ((cache = hash_table[bucket++]))
! 255: break;
! 256: }
! 257:
! 258: return cache;
! 259: }
! 260:
! 261: static int is_outdated_cname_pointer(struct crec *crecp)
! 262: {
! 263: if (!(crecp->flags & F_CNAME))
! 264: return 0;
! 265:
! 266: /* NB. record may be reused as DS or DNSKEY, where uid is
! 267: overloaded for something completely different */
! 268: if (crecp->addr.cname.cache &&
! 269: (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
! 270: crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
! 271: return 0;
! 272:
! 273: return 1;
! 274: }
! 275:
! 276: static int is_expired(time_t now, struct crec *crecp)
! 277: {
! 278: if (crecp->flags & F_IMMORTAL)
! 279: return 0;
! 280:
! 281: if (difftime(now, crecp->ttd) < 0)
! 282: return 0;
! 283:
! 284: return 1;
! 285: }
! 286:
! 287: static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
! 288: {
! 289: /* Scan and remove old entries.
! 290: If (flags & F_FORWARD) then remove any forward entries for name and any expired
! 291: entries but only in the same hash bucket as name.
! 292: If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
! 293: entries in the whole cache.
! 294: If (flags == 0) remove any expired entries in the whole cache.
! 295:
! 296: In the flags & F_FORWARD case, the return code is valid, and returns zero if the
! 297: name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
! 298:
! 299: We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
! 300: so that when we hit an entry which isn't reverse and is immortal, we're done. */
! 301:
! 302: struct crec *crecp, **up;
! 303:
! 304: if (flags & F_FORWARD)
! 305: {
! 306: for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
! 307: if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
! 308: {
! 309: *up = crecp->hash_next;
! 310: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 311: {
! 312: cache_unlink(crecp);
! 313: cache_free(crecp);
! 314: }
! 315: }
! 316: else if ((crecp->flags & F_FORWARD) &&
! 317: ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&
! 318: hostname_isequal(cache_get_name(crecp), name))
! 319: {
! 320: if (crecp->flags & (F_HOSTS | F_DHCP))
! 321: return 0;
! 322: *up = crecp->hash_next;
! 323: cache_unlink(crecp);
! 324: cache_free(crecp);
! 325: }
! 326: else
! 327: up = &crecp->hash_next;
! 328: }
! 329: else
! 330: {
! 331: int i;
! 332: #ifdef HAVE_IPV6
! 333: int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
! 334: #else
! 335: int addrlen = INADDRSZ;
! 336: #endif
! 337: for (i = 0; i < hash_size; i++)
! 338: for (crecp = hash_table[i], up = &hash_table[i];
! 339: crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
! 340: crecp = crecp->hash_next)
! 341: if (is_expired(now, crecp))
! 342: {
! 343: *up = crecp->hash_next;
! 344: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 345: {
! 346: cache_unlink(crecp);
! 347: cache_free(crecp);
! 348: }
! 349: }
! 350: else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
! 351: (flags & crecp->flags & F_REVERSE) &&
! 352: (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
! 353: memcmp(&crecp->addr.addr, addr, addrlen) == 0)
! 354: {
! 355: *up = crecp->hash_next;
! 356: cache_unlink(crecp);
! 357: cache_free(crecp);
! 358: }
! 359: else
! 360: up = &crecp->hash_next;
! 361: }
! 362:
! 363: return 1;
! 364: }
! 365:
! 366: /* Note: The normal calling sequence is
! 367: cache_start_insert
! 368: cache_insert * n
! 369: cache_end_insert
! 370:
! 371: but an abort can cause the cache_end_insert to be missed
! 372: in which can the next cache_start_insert cleans things up. */
! 373:
! 374: void cache_start_insert(void)
! 375: {
! 376: /* Free any entries which didn't get committed during the last
! 377: insert due to error.
! 378: */
! 379: while (new_chain)
! 380: {
! 381: struct crec *tmp = new_chain->next;
! 382: cache_free(new_chain);
! 383: new_chain = tmp;
! 384: }
! 385: new_chain = NULL;
! 386: insert_error = 0;
! 387: }
! 388:
! 389: struct crec *cache_insert(char *name, struct all_addr *addr,
! 390: time_t now, unsigned long ttl, unsigned short flags)
! 391: {
! 392: struct crec *new;
! 393: union bigname *big_name = NULL;
! 394: int freed_all = flags & F_REVERSE;
! 395: int free_avail = 0;
! 396:
! 397: if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
! 398: ttl = daemon->max_cache_ttl;
! 399:
! 400: /* Don't log keys */
! 401: if (flags & (F_IPV4 | F_IPV6))
! 402: log_query(flags | F_UPSTREAM, name, addr, NULL);
! 403:
! 404: /* if previous insertion failed give up now. */
! 405: if (insert_error)
! 406: return NULL;
! 407:
! 408: /* First remove any expired entries and entries for the name/address we
! 409: are currently inserting. Fail is we attempt to delete a name from
! 410: /etc/hosts or DHCP. */
! 411: if (!cache_scan_free(name, addr, now, flags))
! 412: {
! 413: insert_error = 1;
! 414: return NULL;
! 415: }
! 416:
! 417: /* Now get a cache entry from the end of the LRU list */
! 418: while (1) {
! 419: if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
! 420: {
! 421: insert_error = 1;
! 422: return NULL;
! 423: }
! 424:
! 425: /* End of LRU list is still in use: if we didn't scan all the hash
! 426: chains for expired entries do that now. If we already tried that
! 427: then it's time to start spilling things. */
! 428:
! 429: if (new->flags & (F_FORWARD | F_REVERSE))
! 430: {
! 431: /* If free_avail set, we believe that an entry has been freed.
! 432: Bugs have been known to make this not true, resulting in
! 433: a tight loop here. If that happens, abandon the
! 434: insert. Once in this state, all inserts will probably fail. */
! 435: if (free_avail)
! 436: {
! 437: insert_error = 1;
! 438: return NULL;
! 439: }
! 440:
! 441: if (freed_all)
! 442: {
! 443: free_avail = 1; /* Must be free space now. */
! 444: cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
! 445: cache_live_freed++;
! 446: }
! 447: else
! 448: {
! 449: cache_scan_free(NULL, NULL, now, 0);
! 450: freed_all = 1;
! 451: }
! 452: continue;
! 453: }
! 454:
! 455: /* Check if we need to and can allocate extra memory for a long name.
! 456: If that fails, give up now. */
! 457: if (name && (strlen(name) > SMALLDNAME-1))
! 458: {
! 459: if (big_free)
! 460: {
! 461: big_name = big_free;
! 462: big_free = big_free->next;
! 463: }
! 464: else if (!bignames_left ||
! 465: !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
! 466: {
! 467: insert_error = 1;
! 468: return NULL;
! 469: }
! 470: else
! 471: bignames_left--;
! 472:
! 473: }
! 474:
! 475: /* Got the rest: finally grab entry. */
! 476: cache_unlink(new);
! 477: break;
! 478: }
! 479:
! 480: new->flags = flags;
! 481: if (big_name)
! 482: {
! 483: new->name.bname = big_name;
! 484: new->flags |= F_BIGNAME;
! 485: }
! 486:
! 487: if (name)
! 488: strcpy(cache_get_name(new), name);
! 489: else
! 490: *cache_get_name(new) = 0;
! 491:
! 492: if (addr)
! 493: new->addr.addr = *addr;
! 494:
! 495: new->ttd = now + (time_t)ttl;
! 496: new->next = new_chain;
! 497: new_chain = new;
! 498:
! 499: return new;
! 500: }
! 501:
! 502: /* after end of insertion, commit the new entries */
! 503: void cache_end_insert(void)
! 504: {
! 505: if (insert_error)
! 506: return;
! 507:
! 508: while (new_chain)
! 509: {
! 510: struct crec *tmp = new_chain->next;
! 511: /* drop CNAMEs which didn't find a target. */
! 512: if (is_outdated_cname_pointer(new_chain))
! 513: cache_free(new_chain);
! 514: else
! 515: {
! 516: cache_hash(new_chain);
! 517: cache_link(new_chain);
! 518: cache_inserted++;
! 519: }
! 520: new_chain = tmp;
! 521: }
! 522: new_chain = NULL;
! 523: }
! 524:
! 525: struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
! 526: {
! 527: struct crec *ans;
! 528:
! 529: if (crecp) /* iterating */
! 530: ans = crecp->next;
! 531: else
! 532: {
! 533: /* first search, look for relevant entries and push to top of list
! 534: also free anything which has expired */
! 535: struct crec *next, **up, **insert = NULL, **chainp = &ans;
! 536: unsigned short ins_flags = 0;
! 537:
! 538: for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
! 539: {
! 540: next = crecp->hash_next;
! 541:
! 542: if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
! 543: {
! 544: if ((crecp->flags & F_FORWARD) &&
! 545: (crecp->flags & prot) &&
! 546: hostname_isequal(cache_get_name(crecp), name))
! 547: {
! 548: if (crecp->flags & (F_HOSTS | F_DHCP))
! 549: {
! 550: *chainp = crecp;
! 551: chainp = &crecp->next;
! 552: }
! 553: else
! 554: {
! 555: cache_unlink(crecp);
! 556: cache_link(crecp);
! 557: }
! 558:
! 559: /* Move all but the first entry up the hash chain
! 560: this implements round-robin.
! 561: Make sure that re-ordering doesn't break the hash-chain
! 562: order invariants.
! 563: */
! 564: if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
! 565: {
! 566: *up = crecp->hash_next;
! 567: crecp->hash_next = *insert;
! 568: *insert = crecp;
! 569: insert = &crecp->hash_next;
! 570: }
! 571: else
! 572: {
! 573: if (!insert)
! 574: {
! 575: insert = up;
! 576: ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
! 577: }
! 578: up = &crecp->hash_next;
! 579: }
! 580: }
! 581: else
! 582: /* case : not expired, incorrect entry. */
! 583: up = &crecp->hash_next;
! 584: }
! 585: else
! 586: {
! 587: /* expired entry, free it */
! 588: *up = crecp->hash_next;
! 589: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 590: {
! 591: cache_unlink(crecp);
! 592: cache_free(crecp);
! 593: }
! 594: }
! 595: }
! 596:
! 597: *chainp = cache_head;
! 598: }
! 599:
! 600: if (ans &&
! 601: (ans->flags & F_FORWARD) &&
! 602: (ans->flags & prot) &&
! 603: hostname_isequal(cache_get_name(ans), name))
! 604: return ans;
! 605:
! 606: return NULL;
! 607: }
! 608:
! 609: struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
! 610: time_t now, unsigned short prot)
! 611: {
! 612: struct crec *ans;
! 613: #ifdef HAVE_IPV6
! 614: int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
! 615: #else
! 616: int addrlen = INADDRSZ;
! 617: #endif
! 618:
! 619: if (crecp) /* iterating */
! 620: ans = crecp->next;
! 621: else
! 622: {
! 623: /* first search, look for relevant entries and push to top of list
! 624: also free anything which has expired. All the reverse entries are at the
! 625: start of the hash chain, so we can give up when we find the first
! 626: non-REVERSE one. */
! 627: int i;
! 628: struct crec **up, **chainp = &ans;
! 629:
! 630: for (i=0; i<hash_size; i++)
! 631: for (crecp = hash_table[i], up = &hash_table[i];
! 632: crecp && (crecp->flags & F_REVERSE);
! 633: crecp = crecp->hash_next)
! 634: if (!is_expired(now, crecp))
! 635: {
! 636: if ((crecp->flags & prot) &&
! 637: memcmp(&crecp->addr.addr, addr, addrlen) == 0)
! 638: {
! 639: if (crecp->flags & (F_HOSTS | F_DHCP))
! 640: {
! 641: *chainp = crecp;
! 642: chainp = &crecp->next;
! 643: }
! 644: else
! 645: {
! 646: cache_unlink(crecp);
! 647: cache_link(crecp);
! 648: }
! 649: }
! 650: up = &crecp->hash_next;
! 651: }
! 652: else
! 653: {
! 654: *up = crecp->hash_next;
! 655: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 656: {
! 657: cache_unlink(crecp);
! 658: cache_free(crecp);
! 659: }
! 660: }
! 661:
! 662: *chainp = cache_head;
! 663: }
! 664:
! 665: if (ans &&
! 666: (ans->flags & F_REVERSE) &&
! 667: (ans->flags & prot) &&
! 668: memcmp(&ans->addr.addr, addr, addrlen) == 0)
! 669: return ans;
! 670:
! 671: return NULL;
! 672: }
! 673:
! 674: static void add_hosts_cname(struct crec *target)
! 675: {
! 676: struct crec *crec;
! 677: struct cname *a;
! 678:
! 679: for (a = daemon->cnames; a; a = a->next)
! 680: if (hostname_isequal(cache_get_name(target), a->target) &&
! 681: (crec = whine_malloc(sizeof(struct crec))))
! 682: {
! 683: crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
! 684: crec->name.namep = a->alias;
! 685: crec->addr.cname.cache = target;
! 686: crec->addr.cname.uid = target->uid;
! 687: cache_hash(crec);
! 688: add_hosts_cname(crec); /* handle chains */
! 689: }
! 690: }
! 691:
! 692: static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
! 693: int index, struct crec **rhash, int hashsz)
! 694: {
! 695: struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
! 696: int i, nameexists = 0;
! 697: unsigned int j;
! 698:
! 699: /* Remove duplicates in hosts files. */
! 700: if (lookup && (lookup->flags & F_HOSTS))
! 701: {
! 702: nameexists = 1;
! 703: if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
! 704: {
! 705: free(cache);
! 706: return;
! 707: }
! 708: }
! 709:
! 710: /* Ensure there is only one address -> name mapping (first one trumps)
! 711: We do this by steam here, The entries are kept in hash chains, linked
! 712: by ->next (which is unused at this point) held in hash buckets in
! 713: the array rhash, hashed on address. Note that rhash and the values
! 714: in ->next are only valid whilst reading hosts files: the buckets are
! 715: then freed, and the ->next pointer used for other things.
! 716:
! 717: Only insert each unique address once into this hashing structure.
! 718:
! 719: This complexity avoids O(n^2) divergent CPU use whilst reading
! 720: large (10000 entry) hosts files. */
! 721:
! 722: /* hash address */
! 723: for (j = 0, i = 0; i < addrlen; i++)
! 724: j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
! 725:
! 726: for (lookup = rhash[j]; lookup; lookup = lookup->next)
! 727: if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
! 728: memcmp(&lookup->addr.addr, addr, addrlen) == 0)
! 729: {
! 730: cache->flags &= ~F_REVERSE;
! 731: break;
! 732: }
! 733:
! 734: /* maintain address hash chain, insert new unique address */
! 735: if (!lookup)
! 736: {
! 737: cache->next = rhash[j];
! 738: rhash[j] = cache;
! 739: }
! 740:
! 741: cache->uid = index;
! 742: memcpy(&cache->addr.addr, addr, addrlen);
! 743: cache_hash(cache);
! 744:
! 745: /* don't need to do alias stuff for second and subsequent addresses. */
! 746: if (!nameexists)
! 747: add_hosts_cname(cache);
! 748: }
! 749:
! 750: static int eatspace(FILE *f)
! 751: {
! 752: int c, nl = 0;
! 753:
! 754: while (1)
! 755: {
! 756: if ((c = getc(f)) == '#')
! 757: while (c != '\n' && c != EOF)
! 758: c = getc(f);
! 759:
! 760: if (c == EOF)
! 761: return 1;
! 762:
! 763: if (!isspace(c))
! 764: {
! 765: ungetc(c, f);
! 766: return nl;
! 767: }
! 768:
! 769: if (c == '\n')
! 770: nl = 1;
! 771: }
! 772: }
! 773:
! 774: static int gettok(FILE *f, char *token)
! 775: {
! 776: int c, count = 0;
! 777:
! 778: while (1)
! 779: {
! 780: if ((c = getc(f)) == EOF)
! 781: return (count == 0) ? EOF : 1;
! 782:
! 783: if (isspace(c) || c == '#')
! 784: {
! 785: ungetc(c, f);
! 786: return eatspace(f);
! 787: }
! 788:
! 789: if (count < (MAXDNAME - 1))
! 790: {
! 791: token[count++] = c;
! 792: token[count] = 0;
! 793: }
! 794: }
! 795: }
! 796:
! 797: static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
! 798: {
! 799: FILE *f = fopen(filename, "r");
! 800: char *token = daemon->namebuff, *domain_suffix = NULL;
! 801: int addr_count = 0, name_count = cache_size, lineno = 0;
! 802: unsigned short flags = 0;
! 803: struct all_addr addr;
! 804: int atnl, addrlen = 0;
! 805:
! 806: if (!f)
! 807: {
! 808: my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
! 809: return 0;
! 810: }
! 811:
! 812: eatspace(f);
! 813:
! 814: while ((atnl = gettok(f, token)) != EOF)
! 815: {
! 816: lineno++;
! 817:
! 818: if (inet_pton(AF_INET, token, &addr) > 0)
! 819: {
! 820: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
! 821: addrlen = INADDRSZ;
! 822: domain_suffix = get_domain(addr.addr.addr4);
! 823: }
! 824: #ifdef HAVE_IPV6
! 825: else if (inet_pton(AF_INET6, token, &addr) > 0)
! 826: {
! 827: flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
! 828: addrlen = IN6ADDRSZ;
! 829: domain_suffix = get_domain6(&addr.addr.addr6);
! 830: }
! 831: #endif
! 832: else
! 833: {
! 834: my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
! 835: while (atnl == 0)
! 836: atnl = gettok(f, token);
! 837: continue;
! 838: }
! 839:
! 840: addr_count++;
! 841:
! 842: /* rehash every 1000 names. */
! 843: if ((name_count - cache_size) > 1000)
! 844: {
! 845: rehash(name_count);
! 846: cache_size = name_count;
! 847: }
! 848:
! 849: while (atnl == 0)
! 850: {
! 851: struct crec *cache;
! 852: int fqdn, nomem;
! 853: char *canon;
! 854:
! 855: if ((atnl = gettok(f, token)) == EOF)
! 856: break;
! 857:
! 858: fqdn = !!strchr(token, '.');
! 859:
! 860: if ((canon = canonicalise(token, &nomem)))
! 861: {
! 862: /* If set, add a version of the name with a default domain appended */
! 863: if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
! 864: (cache = whine_malloc(sizeof(struct crec) +
! 865: strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
! 866: {
! 867: strcpy(cache->name.sname, canon);
! 868: strcat(cache->name.sname, ".");
! 869: strcat(cache->name.sname, domain_suffix);
! 870: cache->flags = flags;
! 871: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
! 872: name_count++;
! 873: }
! 874: if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
! 875: {
! 876: strcpy(cache->name.sname, canon);
! 877: cache->flags = flags;
! 878: add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
! 879: name_count++;
! 880: }
! 881: free(canon);
! 882:
! 883: }
! 884: else if (!nomem)
! 885: my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
! 886: }
! 887: }
! 888:
! 889: fclose(f);
! 890: rehash(name_count);
! 891:
! 892: my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
! 893:
! 894: return name_count;
! 895: }
! 896:
! 897: void cache_reload(void)
! 898: {
! 899: struct crec *cache, **up, *tmp;
! 900: int revhashsz, i, total_size = daemon->cachesize;
! 901: struct hostsfile *ah;
! 902: struct host_record *hr;
! 903: struct name_list *nl;
! 904:
! 905: cache_inserted = cache_live_freed = 0;
! 906:
! 907: for (i=0; i<hash_size; i++)
! 908: for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
! 909: {
! 910: tmp = cache->hash_next;
! 911: if (cache->flags & F_HOSTS)
! 912: {
! 913: *up = cache->hash_next;
! 914: free(cache);
! 915: }
! 916: else if (!(cache->flags & F_DHCP))
! 917: {
! 918: *up = cache->hash_next;
! 919: if (cache->flags & F_BIGNAME)
! 920: {
! 921: cache->name.bname->next = big_free;
! 922: big_free = cache->name.bname;
! 923: }
! 924: cache->flags = 0;
! 925: }
! 926: else
! 927: up = &cache->hash_next;
! 928: }
! 929:
! 930: /* borrow the packet buffer for a temporary by-address hash */
! 931: memset(daemon->packet, 0, daemon->packet_buff_sz);
! 932: revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
! 933: /* we overwrote the buffer... */
! 934: daemon->srv_save = NULL;
! 935:
! 936: /* Do host_records in config. */
! 937: for (hr = daemon->host_records; hr; hr = hr->next)
! 938: for (nl = hr->names; nl; nl = nl->next)
! 939: {
! 940: if (hr->addr.s_addr != 0 &&
! 941: (cache = whine_malloc(sizeof(struct crec))))
! 942: {
! 943: cache->name.namep = nl->name;
! 944: cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
! 945: add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
! 946: }
! 947: #ifdef HAVE_IPV6
! 948: if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
! 949: (cache = whine_malloc(sizeof(struct crec))))
! 950: {
! 951: cache->name.namep = nl->name;
! 952: cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
! 953: add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
! 954: }
! 955: #endif
! 956: }
! 957:
! 958: if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
! 959: {
! 960: if (daemon->cachesize > 0)
! 961: my_syslog(LOG_INFO, _("cleared cache"));
! 962: return;
! 963: }
! 964:
! 965: if (!option_bool(OPT_NO_HOSTS))
! 966: total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
! 967:
! 968: daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
! 969: for (ah = daemon->addn_hosts; ah; ah = ah->next)
! 970: if (!(ah->flags & AH_INACTIVE))
! 971: total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
! 972: }
! 973:
! 974: char *get_domain(struct in_addr addr)
! 975: {
! 976: struct cond_domain *c;
! 977:
! 978: for (c = daemon->cond_domain; c; c = c->next)
! 979: if (!c->is6 &&
! 980: ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
! 981: ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
! 982: return c->domain;
! 983:
! 984: return daemon->domain_suffix;
! 985: }
! 986:
! 987:
! 988: #ifdef HAVE_IPV6
! 989: char *get_domain6(struct in6_addr *addr)
! 990: {
! 991: struct cond_domain *c;
! 992:
! 993: u64 addrpart = addr6part(addr);
! 994:
! 995: for (c = daemon->cond_domain; c; c = c->next)
! 996: if (c->is6 &&
! 997: is_same_net6(addr, &c->start6, 64) &&
! 998: addrpart >= addr6part(&c->start6) &&
! 999: addrpart <= addr6part(&c->end6))
! 1000: return c->domain;
! 1001:
! 1002: return daemon->domain_suffix;
! 1003: }
! 1004: #endif
! 1005:
! 1006: #ifdef HAVE_DHCP
! 1007: struct in_addr a_record_from_hosts(char *name, time_t now)
! 1008: {
! 1009: struct crec *crecp = NULL;
! 1010: struct in_addr ret;
! 1011:
! 1012: while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
! 1013: if (crecp->flags & F_HOSTS)
! 1014: return *(struct in_addr *)&crecp->addr;
! 1015:
! 1016: my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
! 1017:
! 1018: ret.s_addr = 0;
! 1019: return ret;
! 1020: }
! 1021:
! 1022: void cache_unhash_dhcp(void)
! 1023: {
! 1024: struct crec *cache, **up;
! 1025: int i;
! 1026:
! 1027: for (i=0; i<hash_size; i++)
! 1028: for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
! 1029: if (cache->flags & F_DHCP)
! 1030: {
! 1031: *up = cache->hash_next;
! 1032: cache->next = dhcp_spare;
! 1033: dhcp_spare = cache;
! 1034: }
! 1035: else
! 1036: up = &cache->hash_next;
! 1037: }
! 1038:
! 1039: static void add_dhcp_cname(struct crec *target, time_t ttd)
! 1040: {
! 1041: struct crec *aliasc;
! 1042: struct cname *a;
! 1043:
! 1044: for (a = daemon->cnames; a; a = a->next)
! 1045: if (hostname_isequal(cache_get_name(target), a->target))
! 1046: {
! 1047: if ((aliasc = dhcp_spare))
! 1048: dhcp_spare = dhcp_spare->next;
! 1049: else /* need new one */
! 1050: aliasc = whine_malloc(sizeof(struct crec));
! 1051:
! 1052: if (aliasc)
! 1053: {
! 1054: aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
! 1055: if (ttd == 0)
! 1056: aliasc->flags |= F_IMMORTAL;
! 1057: else
! 1058: aliasc->ttd = ttd;
! 1059: aliasc->name.namep = a->alias;
! 1060: aliasc->addr.cname.cache = target;
! 1061: aliasc->addr.cname.uid = target->uid;
! 1062: cache_hash(aliasc);
! 1063: add_dhcp_cname(aliasc, ttd);
! 1064: }
! 1065: }
! 1066: }
! 1067:
! 1068: void cache_add_dhcp_entry(char *host_name, int prot,
! 1069: struct all_addr *host_address, time_t ttd)
! 1070: {
! 1071: struct crec *crec = NULL, *fail_crec = NULL;
! 1072: unsigned short flags = F_IPV4;
! 1073: int in_hosts = 0;
! 1074: size_t addrlen = sizeof(struct in_addr);
! 1075:
! 1076: #ifdef HAVE_IPV6
! 1077: if (prot == AF_INET6)
! 1078: {
! 1079: flags = F_IPV6;
! 1080: addrlen = sizeof(struct in6_addr);
! 1081: }
! 1082: #endif
! 1083:
! 1084: inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
! 1085:
! 1086: while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
! 1087: {
! 1088: /* check all addresses associated with name */
! 1089: if (crec->flags & F_HOSTS)
! 1090: {
! 1091: if (crec->flags & F_CNAME)
! 1092: my_syslog(MS_DHCP | LOG_WARNING,
! 1093: _("%s is a CNAME, not giving it to the DHCP lease of %s"),
! 1094: host_name, daemon->addrbuff);
! 1095: else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
! 1096: in_hosts = 1;
! 1097: else
! 1098: fail_crec = crec;
! 1099: }
! 1100: else if (!(crec->flags & F_DHCP))
! 1101: {
! 1102: cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
! 1103: /* scan_free deletes all addresses associated with name */
! 1104: break;
! 1105: }
! 1106: }
! 1107:
! 1108: /* if in hosts, don't need DHCP record */
! 1109: if (in_hosts)
! 1110: return;
! 1111:
! 1112: /* Name in hosts, address doesn't match */
! 1113: if (fail_crec)
! 1114: {
! 1115: inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
! 1116: my_syslog(MS_DHCP | LOG_WARNING,
! 1117: _("not giving name %s to the DHCP lease of %s because "
! 1118: "the name exists in %s with address %s"),
! 1119: host_name, daemon->addrbuff,
! 1120: record_source(fail_crec->uid), daemon->namebuff);
! 1121: return;
! 1122: }
! 1123:
! 1124: if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
! 1125: {
! 1126: if (crec->flags & F_NEG)
! 1127: {
! 1128: flags |= F_REVERSE;
! 1129: cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
! 1130: }
! 1131: }
! 1132: else
! 1133: flags |= F_REVERSE;
! 1134:
! 1135: if ((crec = dhcp_spare))
! 1136: dhcp_spare = dhcp_spare->next;
! 1137: else /* need new one */
! 1138: crec = whine_malloc(sizeof(struct crec));
! 1139:
! 1140: if (crec) /* malloc may fail */
! 1141: {
! 1142: crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
! 1143: if (ttd == 0)
! 1144: crec->flags |= F_IMMORTAL;
! 1145: else
! 1146: crec->ttd = ttd;
! 1147: crec->addr.addr = *host_address;
! 1148: crec->name.namep = host_name;
! 1149: crec->uid = uid++;
! 1150: cache_hash(crec);
! 1151:
! 1152: add_dhcp_cname(crec, ttd);
! 1153: }
! 1154: }
! 1155: #endif
! 1156:
! 1157:
! 1158: void dump_cache(time_t now)
! 1159: {
! 1160: struct server *serv, *serv1;
! 1161:
! 1162: my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
! 1163: my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
! 1164: daemon->cachesize, cache_live_freed, cache_inserted);
! 1165: my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
! 1166: daemon->queries_forwarded, daemon->local_answer);
! 1167:
! 1168: /* sum counts from different records for same server */
! 1169: for (serv = daemon->servers; serv; serv = serv->next)
! 1170: serv->flags &= ~SERV_COUNTED;
! 1171:
! 1172: for (serv = daemon->servers; serv; serv = serv->next)
! 1173: if (!(serv->flags &
! 1174: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
! 1175: {
! 1176: int port;
! 1177: unsigned int queries = 0, failed_queries = 0;
! 1178: for (serv1 = serv; serv1; serv1 = serv1->next)
! 1179: if (!(serv1->flags &
! 1180: (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
! 1181: sockaddr_isequal(&serv->addr, &serv1->addr))
! 1182: {
! 1183: serv1->flags |= SERV_COUNTED;
! 1184: queries += serv1->queries;
! 1185: failed_queries += serv1->failed_queries;
! 1186: }
! 1187: port = prettyprint_addr(&serv->addr, daemon->addrbuff);
! 1188: my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
! 1189: }
! 1190:
! 1191: if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
! 1192: {
! 1193: struct crec *cache ;
! 1194: int i;
! 1195: my_syslog(LOG_INFO, "Host Address Flags Expires");
! 1196:
! 1197: for (i=0; i<hash_size; i++)
! 1198: for (cache = hash_table[i]; cache; cache = cache->hash_next)
! 1199: {
! 1200: char *a, *p = daemon->namebuff;
! 1201: p += sprintf(p, "%-40.40s ", cache_get_name(cache));
! 1202: if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
! 1203: a = "";
! 1204: else if (cache->flags & F_CNAME)
! 1205: {
! 1206: a = "";
! 1207: if (!is_outdated_cname_pointer(cache))
! 1208: a = cache_get_name(cache->addr.cname.cache);
! 1209: }
! 1210: #ifdef HAVE_DNSSEC
! 1211: else if (cache->flags & F_DNSKEY)
! 1212: {
! 1213: a = daemon->addrbuff;
! 1214: sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);
! 1215: }
! 1216: else if (cache->flags & F_DS)
! 1217: {
! 1218: a = daemon->addrbuff;
! 1219: sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,
! 1220: cache->addr.key.algo, cache->addr.key.digest, cache->uid);
! 1221: }
! 1222: #endif
! 1223: else
! 1224: {
! 1225: a = daemon->addrbuff;
! 1226: if (cache->flags & F_IPV4)
! 1227: inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
! 1228: #ifdef HAVE_IPV6
! 1229: else if (cache->flags & F_IPV6)
! 1230: inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
! 1231: #endif
! 1232: }
! 1233:
! 1234: p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s ", a,
! 1235: cache->flags & F_IPV4 ? "4" : "",
! 1236: cache->flags & F_IPV6 ? "6" : "",
! 1237: cache->flags & F_DNSKEY ? "K" : "",
! 1238: cache->flags & F_DS ? "S" : "",
! 1239: cache->flags & F_CNAME ? "C" : "",
! 1240: cache->flags & F_FORWARD ? "F" : " ",
! 1241: cache->flags & F_REVERSE ? "R" : " ",
! 1242: cache->flags & F_IMMORTAL ? "I" : " ",
! 1243: cache->flags & F_DHCP ? "D" : " ",
! 1244: cache->flags & F_NEG ? "N" : " ",
! 1245: cache->flags & F_NXDOMAIN ? "X" : " ",
! 1246: cache->flags & F_HOSTS ? "H" : " ",
! 1247: cache->flags & F_DNSSECOK ? "V" : " ");
! 1248: #ifdef HAVE_BROKEN_RTC
! 1249: p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
! 1250: #else
! 1251: p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
! 1252: /* ctime includes trailing \n - eat it */
! 1253: *(p-1) = 0;
! 1254: #endif
! 1255: my_syslog(LOG_INFO, daemon->namebuff);
! 1256: }
! 1257: }
! 1258: }
! 1259:
! 1260: char *record_source(int index)
! 1261: {
! 1262: struct hostsfile *ah;
! 1263:
! 1264: if (index == 0)
! 1265: return HOSTSFILE;
! 1266:
! 1267: for (ah = daemon->addn_hosts; ah; ah = ah->next)
! 1268: if (ah->index == index)
! 1269: return ah->fname;
! 1270:
! 1271: return "<unknown>";
! 1272: }
! 1273:
! 1274: void querystr(char *desc, char *str, unsigned short type)
! 1275: {
! 1276: unsigned int i;
! 1277:
! 1278: sprintf(str, "%s[type=%d]", desc, type);
! 1279: for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
! 1280: if (typestr[i].type == type)
! 1281: sprintf(str,"%s[%s]", desc, typestr[i].name);
! 1282: }
! 1283:
! 1284: void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
! 1285: {
! 1286: char *source, *dest = daemon->addrbuff;
! 1287: char *verb = "is";
! 1288:
! 1289: if (!option_bool(OPT_LOG))
! 1290: return;
! 1291:
! 1292: if (addr)
! 1293: {
! 1294: #ifdef HAVE_IPV6
! 1295: inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
! 1296: addr, daemon->addrbuff, ADDRSTRLEN);
! 1297: #else
! 1298: strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
! 1299: #endif
! 1300: }
! 1301:
! 1302: if (flags & F_REVERSE)
! 1303: {
! 1304: dest = name;
! 1305: name = daemon->addrbuff;
! 1306: }
! 1307:
! 1308: if (flags & F_NEG)
! 1309: {
! 1310: if (flags & F_NXDOMAIN)
! 1311: {
! 1312: if (flags & F_IPV4)
! 1313: dest = "NXDOMAIN-IPv4";
! 1314: else if (flags & F_IPV6)
! 1315: dest = "NXDOMAIN-IPv6";
! 1316: else
! 1317: dest = "NXDOMAIN";
! 1318: }
! 1319: else
! 1320: {
! 1321: if (flags & F_IPV4)
! 1322: dest = "NODATA-IPv4";
! 1323: else if (flags & F_IPV6)
! 1324: dest = "NODATA-IPv6";
! 1325: else
! 1326: dest = "NODATA";
! 1327: }
! 1328: }
! 1329: else if (flags & F_CNAME)
! 1330: dest = "<CNAME>";
! 1331: else if (flags & F_RRNAME)
! 1332: dest = arg;
! 1333:
! 1334: if (flags & F_CONFIG)
! 1335: source = "config";
! 1336: else if (flags & F_DHCP)
! 1337: source = "DHCP";
! 1338: else if (flags & F_HOSTS)
! 1339: source = arg;
! 1340: else if (flags & F_UPSTREAM)
! 1341: source = "reply";
! 1342: else if (flags & F_AUTH)
! 1343: source = "auth";
! 1344: else if (flags & F_SERVER)
! 1345: {
! 1346: source = "forwarded";
! 1347: verb = "to";
! 1348: }
! 1349: else if (flags & F_QUERY)
! 1350: {
! 1351: source = arg;
! 1352: verb = "from";
! 1353: }
! 1354: else
! 1355: source = "cached";
! 1356:
! 1357: if (strlen(name) == 0)
! 1358: name = ".";
! 1359:
! 1360: my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
! 1361: }
! 1362:
! 1363: #ifdef HAVE_DNSSEC
! 1364: struct keydata *keydata_alloc(char *data, size_t len)
! 1365: {
! 1366: struct keydata *block, *ret = NULL;
! 1367: struct keydata **prev = &ret;
! 1368: while (len > 0)
! 1369: {
! 1370: if (keyblock_free)
! 1371: {
! 1372: block = keyblock_free;
! 1373: keyblock_free = block->next;
! 1374: }
! 1375: else
! 1376: block = whine_malloc(sizeof(struct keydata));
! 1377:
! 1378: if (!block)
! 1379: {
! 1380: /* failed to alloc, free partial chain */
! 1381: keydata_free(ret);
! 1382: return NULL;
! 1383: }
! 1384:
! 1385: memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len);
! 1386: data += KEYBLOCK_LEN;
! 1387: len -= KEYBLOCK_LEN;
! 1388: *prev = block;
! 1389: prev = &block->next;
! 1390: block->next = NULL;
! 1391: }
! 1392:
! 1393: return ret;
! 1394: }
! 1395:
! 1396: void keydata_free(struct keydata *blocks)
! 1397: {
! 1398: struct keydata *tmp;
! 1399:
! 1400: if (blocks)
! 1401: {
! 1402: for (tmp = blocks; tmp->next; tmp = tmp->next);
! 1403: tmp->next = keyblock_free;
! 1404: keyblock_free = blocks;
! 1405: }
! 1406: }
! 1407: #endif
! 1408:
! 1409:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>