1/* dnsmasq is Copyright (c) 2000-2005 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. 6 7 This program is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 GNU General Public License for more details. 11*/ 12 13#include "dnsmasq.h" 14 15static struct crec *cache_head, *cache_tail, **hash_table; 16static struct crec *dhcp_inuse, *dhcp_spare, *new_chain; 17static int cache_inserted, cache_live_freed, insert_error; 18static union bigname *big_free; 19static int bignames_left, log_queries, cache_size, hash_size; 20static int uid; 21static char *addrbuff; 22 23static void cache_free(struct crec *crecp); 24static void cache_unlink(struct crec *crecp); 25static void cache_link(struct crec *crecp); 26static char *record_source(struct hostsfile *add_hosts, int index); 27 28void cache_init(int size, int logq) 29{ 30 struct crec *crecp; 31 int i; 32 33 if ((log_queries = logq)) 34 addrbuff = safe_malloc(ADDRSTRLEN); 35 else 36 addrbuff = NULL; 37 38 cache_head = cache_tail = NULL; 39 dhcp_inuse = dhcp_spare = NULL; 40 new_chain = NULL; 41 cache_size = size; 42 big_free = NULL; 43 bignames_left = size/10; 44 uid = 0; 45 46 cache_inserted = cache_live_freed = 0; 47 48 if (cache_size > 0) 49 { 50 crecp = safe_malloc(size*sizeof(struct crec)); 51 52 for (i=0; i<size; i++, crecp++) 53 { 54 cache_link(crecp); 55 crecp->flags = 0; 56 crecp->uid = uid++; 57 } 58 } 59 60 /* hash_size is a power of two. */ 61 for (hash_size = 64; hash_size < cache_size/10; hash_size = hash_size << 1); 62 hash_table = safe_malloc(hash_size*sizeof(struct crec *)); 63 for(i=0; i < hash_size; i++) 64 hash_table[i] = NULL; 65} 66 67static struct crec **hash_bucket(char *name) 68{ 69 unsigned int c, val = 0; 70 71 /* don't use tolower and friends here - they may be messed up by LOCALE */ 72 while((c = (unsigned char) *name++)) 73 if (c >= 'A' && c <= 'Z') 74 val += c + 'a' - 'A'; 75 else 76 val += c; 77 78 /* hash_size is a power of two */ 79 return hash_table + (val & (hash_size - 1)); 80} 81 82static void cache_hash(struct crec *crecp) 83{ 84 struct crec **bucket = hash_bucket(cache_get_name(crecp)); 85 crecp->hash_next = *bucket; 86 *bucket = crecp; 87} 88 89static void cache_free(struct crec *crecp) 90{ 91 crecp->flags &= ~F_FORWARD; 92 crecp->flags &= ~F_REVERSE; 93 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ 94 95 if (cache_tail) 96 cache_tail->next = crecp; 97 else 98 cache_head = crecp; 99 crecp->prev = cache_tail; 100 crecp->next = NULL; 101 cache_tail = crecp; 102 103 /* retrieve big name for further use. */ 104 if (crecp->flags & F_BIGNAME) 105 { 106 crecp->name.bname->next = big_free; 107 big_free = crecp->name.bname; 108 crecp->flags &= ~F_BIGNAME; 109 } 110} 111 112/* insert a new cache entry at the head of the list (youngest entry) */ 113static void cache_link(struct crec *crecp) 114{ 115 if (cache_head) /* check needed for init code */ 116 cache_head->prev = crecp; 117 crecp->next = cache_head; 118 crecp->prev = NULL; 119 cache_head = crecp; 120 if (!cache_tail) 121 cache_tail = crecp; 122} 123 124/* remove an arbitrary cache entry for promotion */ 125static void cache_unlink (struct crec *crecp) 126{ 127 if (crecp->prev) 128 crecp->prev->next = crecp->next; 129 else 130 cache_head = crecp->next; 131 132 if (crecp->next) 133 crecp->next->prev = crecp->prev; 134 else 135 cache_tail = crecp->prev; 136} 137 138char *cache_get_name(struct crec *crecp) 139{ 140 if (crecp->flags & F_BIGNAME) 141 return crecp->name.bname->name; 142 else if (crecp->flags & F_DHCP) 143 return crecp->name.namep; 144 145 return crecp->name.sname; 146} 147 148static int is_outdated_cname_pointer(struct crec *crecp) 149{ 150 struct crec *target = crecp->addr.cname.cache; 151 152 if (!(crecp->flags & F_CNAME)) 153 return 0; 154 155 if (!target) 156 return 1; 157 158 if (crecp->addr.cname.uid == target->uid) 159 return 0; 160 161 return 1; 162} 163 164static int is_expired(time_t now, struct crec *crecp) 165{ 166 if (crecp->flags & F_IMMORTAL) 167 return 0; 168 169 if (difftime(now, crecp->ttd) < 0) 170 return 0; 171 172 return 1; 173} 174 175static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) 176{ 177 /* Scan and remove old entries. 178 If (flags & F_FORWARD) then remove any forward entries for name and any expired 179 entries but only in the same hash bucket as name. 180 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired 181 entries in the whole cache. 182 If (flags == 0) remove any expired entries in the whole cache. 183 184 In the flags & F_FORWARD case, the return code is valid, and returns zero if the 185 name exists in the cache as a HOSTS or DHCP entry (these are never deleted) */ 186 187 struct crec *crecp, **up; 188 189 if (flags & F_FORWARD) 190 { 191 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next) 192 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp)) 193 { 194 *up = crecp->hash_next; 195 if (!(crecp->flags & (F_HOSTS | F_DHCP))) 196 { 197 cache_unlink(crecp); 198 cache_free(crecp); 199 } 200 } 201 else if ((crecp->flags & F_FORWARD) && 202 ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || ((crecp->flags | flags) & F_CNAME)) && 203 hostname_isequal(cache_get_name(crecp), name)) 204 { 205 if (crecp->flags & (F_HOSTS | F_DHCP)) 206 return 0; 207 *up = crecp->hash_next; 208 cache_unlink(crecp); 209 cache_free(crecp); 210 } 211 else 212 up = &crecp->hash_next; 213 } 214 else 215 { 216 int i; 217#ifdef HAVE_IPV6 218 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ; 219#else 220 int addrlen = INADDRSZ; 221#endif 222 for (i = 0; i < hash_size; i++) 223 for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next) 224 if (is_expired(now, crecp)) 225 { 226 *up = crecp->hash_next; 227 if (!(crecp->flags & (F_HOSTS | F_DHCP))) 228 { 229 cache_unlink(crecp); 230 cache_free(crecp); 231 } 232 } 233 else if (!(crecp->flags & (F_HOSTS | F_DHCP)) && 234 (flags & crecp->flags & F_REVERSE) && 235 (flags & crecp->flags & (F_IPV4 | F_IPV6)) && 236 memcmp(&crecp->addr.addr, addr, addrlen) == 0) 237 { 238 *up = crecp->hash_next; 239 cache_unlink(crecp); 240 cache_free(crecp); 241 } 242 else 243 up = &crecp->hash_next; 244 } 245 246 return 1; 247} 248 249/* Note: The normal calling sequence is 250 cache_start_insert 251 cache_insert * n 252 cache_end_insert 253 254 but an abort can cause the cache_end_insert to be missed 255 in which can the next cache_start_insert cleans things up. */ 256 257void cache_start_insert(void) 258{ 259 /* Free any entries which didn't get committed during the last 260 insert due to error. 261 */ 262 while (new_chain) 263 { 264 struct crec *tmp = new_chain->next; 265 cache_free(new_chain); 266 new_chain = tmp; 267 } 268 new_chain = NULL; 269 insert_error = 0; 270} 271 272struct crec *cache_insert(char *name, struct all_addr *addr, 273 time_t now, unsigned long ttl, unsigned short flags) 274{ 275#ifdef HAVE_IPV6 276 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ; 277#else 278 int addrlen = INADDRSZ; 279#endif 280 struct crec *new; 281 union bigname *big_name = NULL; 282 int freed_all = flags & F_REVERSE; 283 284 log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0); 285 286 /* name is needed as workspace by log_query in this case */ 287 if ((flags & F_NEG) && (flags & F_REVERSE)) 288 name = NULL; 289 290 /* CONFIG bit no needed except for logging */ 291 flags &= ~F_CONFIG; 292 293 /* if previous insertion failed give up now. */ 294 if (insert_error) 295 return NULL; 296 297 /* First remove any expired entries and entries for the name/address we 298 are currently inserting. Fail is we attempt to delete a name from 299 /etc/hosts or DHCP. */ 300 if (!cache_scan_free(name, addr, now, flags)) 301 { 302 insert_error = 1; 303 return NULL; 304 } 305 306 /* Now get a cache entry from the end of the LRU list */ 307 while (1) { 308 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */ 309 { 310 insert_error = 1; 311 return NULL; 312 } 313 314 /* End of LRU list is still in use: if we didn't scan all the hash 315 chains for expired entries do that now. If we already tried that 316 then it's time to start spilling things. */ 317 318 if (new->flags & (F_FORWARD | F_REVERSE)) 319 { 320 if (freed_all) 321 { 322 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags); 323 cache_live_freed++; 324 } 325 else 326 { 327 cache_scan_free(NULL, NULL, now, 0); 328 freed_all = 1; 329 } 330 continue; 331 } 332 333 /* Check if we need to and can allocate extra memory for a long name. 334 If that fails, give up now. */ 335 if (name && (strlen(name) > SMALLDNAME-1)) 336 { 337 if (big_free) 338 { 339 big_name = big_free; 340 big_free = big_free->next; 341 } 342 else if (!bignames_left || 343 !(big_name = (union bigname *)malloc(sizeof(union bigname)))) 344 { 345 insert_error = 1; 346 return NULL; 347 } 348 else 349 bignames_left--; 350 351 } 352 353 /* Got the rest: finally grab entry. */ 354 cache_unlink(new); 355 break; 356 } 357 358 new->flags = flags; 359 if (big_name) 360 { 361 new->name.bname = big_name; 362 new->flags |= F_BIGNAME; 363 } 364 if (name) 365 strcpy(cache_get_name(new), name); 366 else 367 *cache_get_name(new) = 0; 368 if (addr) 369 memcpy(&new->addr.addr, addr, addrlen); 370 else 371 new->addr.cname.cache = NULL; 372 373 new->ttd = now + (time_t)ttl; 374 new->next = new_chain; 375 new_chain = new; 376 377 return new; 378} 379 380/* after end of insertion, commit the new entries */ 381void cache_end_insert(void) 382{ 383 if (insert_error) 384 return; 385 386 while (new_chain) 387 { 388 struct crec *tmp = new_chain->next; 389 /* drop CNAMEs which didn't find a target. */ 390 if (is_outdated_cname_pointer(new_chain)) 391 cache_free(new_chain); 392 else 393 { 394 cache_hash(new_chain); 395 cache_link(new_chain); 396 cache_inserted++; 397 } 398 new_chain = tmp; 399 } 400 new_chain = NULL; 401} 402 403struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot) 404{ 405 struct crec *ans; 406 407 if (crecp) /* iterating */ 408 ans = crecp->next; 409 else 410 { 411 /* first search, look for relevant entries and push to top of list 412 also free anything which has expired */ 413 struct crec *next, **up, **insert = NULL, **chainp = &ans; 414 415 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next) 416 { 417 next = crecp->hash_next; 418 419 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp)) 420 { 421 if ((crecp->flags & F_FORWARD) && 422 (crecp->flags & prot) && 423 hostname_isequal(cache_get_name(crecp), name)) 424 { 425 if (crecp->flags & (F_HOSTS | F_DHCP)) 426 { 427 *chainp = crecp; 428 chainp = &crecp->next; 429 } 430 else 431 { 432 cache_unlink(crecp); 433 cache_link(crecp); 434 } 435 436 /* move all but the first entry up the hash chain 437 this implements round-robin */ 438 if (!insert) 439 { 440 insert = up; 441 up = &crecp->hash_next; 442 } 443 else 444 { 445 *up = crecp->hash_next; 446 crecp->hash_next = *insert; 447 *insert = crecp; 448 insert = &crecp->hash_next; 449 } 450 } 451 else 452 /* case : not expired, incorrect entry. */ 453 up = &crecp->hash_next; 454 } 455 else 456 { 457 /* expired entry, free it */ 458 *up = crecp->hash_next; 459 if (!(crecp->flags & (F_HOSTS | F_DHCP))) 460 { 461 cache_unlink(crecp); 462 cache_free(crecp); 463 } 464 } 465 } 466 467 *chainp = cache_head; 468 } 469 470 if (ans && 471 (ans->flags & F_FORWARD) && 472 (ans->flags & prot) && 473 hostname_isequal(cache_get_name(ans), name)) 474 return ans; 475 476 return NULL; 477} 478 479struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, 480 time_t now, unsigned short prot) 481{ 482 struct crec *ans; 483#ifdef HAVE_IPV6 484 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ; 485#else 486 int addrlen = INADDRSZ; 487#endif 488 489 if (crecp) /* iterating */ 490 ans = crecp->next; 491 else 492 { 493 /* first search, look for relevant entries and push to top of list 494 also free anything which has expired */ 495 int i; 496 struct crec **up, **chainp = &ans; 497 498 for(i=0; i<hash_size; i++) 499 for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next) 500 if (!is_expired(now, crecp)) 501 { 502 if ((crecp->flags & F_REVERSE) && 503 (crecp->flags & prot) && 504 memcmp(&crecp->addr.addr, addr, addrlen) == 0) 505 { 506 if (crecp->flags & (F_HOSTS | F_DHCP)) 507 { 508 *chainp = crecp; 509 chainp = &crecp->next; 510 } 511 else 512 { 513 cache_unlink(crecp); 514 cache_link(crecp); 515 } 516 } 517 up = &crecp->hash_next; 518 } 519 else 520 { 521 *up = crecp->hash_next; 522 if (!(crecp->flags & (F_HOSTS | F_DHCP))) 523 { 524 cache_unlink(crecp); 525 cache_free(crecp); 526 } 527 } 528 529 *chainp = cache_head; 530 } 531 532 if (ans && 533 (ans->flags & F_REVERSE) && 534 (ans->flags & prot) && 535 memcmp(&ans->addr.addr, addr, addrlen) == 0) 536 return ans; 537 538 return NULL; 539} 540 541static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, 542 unsigned short flags, int index) 543{ 544 struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6)); 545 546 /* Remove duplicates in hosts files. */ 547 if (lookup && (lookup->flags & F_HOSTS) && 548 memcmp(&lookup->addr.addr, addr, addrlen) == 0) 549 free(cache); 550 else 551 { 552 /* Ensure there is only one address -> name mapping (first one trumps) */ 553 if (cache_find_by_addr(NULL, addr, 0, flags & (F_IPV4 | F_IPV6))) 554 flags &= ~F_REVERSE; 555 cache->flags = flags; 556 cache->uid = index; 557 memcpy(&cache->addr.addr, addr, addrlen); 558 cache_hash(cache); 559 } 560} 561 562static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index) 563{ 564 FILE *f = fopen(filename, "r"); 565 char *line; 566 int count = 0, lineno = 0; 567 568 if (!f) 569 { 570 syslog(LOG_ERR, _("failed to load names from %s: %m"), filename); 571 return; 572 } 573 574 while ((line = fgets(buff, MAXDNAME, f))) 575 { 576 struct all_addr addr; 577 char *token = strtok(line, " \t\n\r"); 578 int addrlen; 579 unsigned short flags; 580 581 lineno++; 582 583 if (!token || (*token == '#')) 584 continue; 585 586#ifdef HAVE_IPV6 587 if (inet_pton(AF_INET, token, &addr) > 0) 588 { 589 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; 590 addrlen = INADDRSZ; 591 } 592 else if (inet_pton(AF_INET6, token, &addr) > 0) 593 { 594 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; 595 addrlen = IN6ADDRSZ; 596 } 597#else 598 if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1) 599 { 600 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; 601 addrlen = INADDRSZ; 602 } 603#endif 604 else 605 { 606 syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); 607 continue; 608 } 609 610 while ((token = strtok(NULL, " \t\n\r")) && (*token != '#')) 611 { 612 struct crec *cache; 613 if (canonicalise(token)) 614 { 615 count++; 616 /* If set, add a version of the name with a default domain appended */ 617 if ((opts & OPT_EXPAND) && domain_suffix && !strchr(token, '.') && 618 (cache = malloc(sizeof(struct crec) + 619 strlen(token)+2+strlen(domain_suffix)-SMALLDNAME))) 620 { 621 strcpy(cache->name.sname, token); 622 strcat(cache->name.sname, "."); 623 strcat(cache->name.sname, domain_suffix); 624 add_hosts_entry(cache, &addr, addrlen, flags, index); 625 } 626 if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME))) 627 { 628 strcpy(cache->name.sname, token); 629 add_hosts_entry(cache, &addr, addrlen, flags, index); 630 } 631 } 632 else 633 syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno); 634 } 635 } 636 637 fclose(f); 638 639 syslog(LOG_INFO, _("read %s - %d addresses"), filename, count); 640} 641 642void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts) 643{ 644 struct crec *cache, **up, *tmp; 645 int i; 646 647 cache_inserted = cache_live_freed = 0; 648 649 for (i=0; i<hash_size; i++) 650 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp) 651 { 652 tmp = cache->hash_next; 653 if (cache->flags & F_HOSTS) 654 { 655 *up = cache->hash_next; 656 free(cache); 657 } 658 else if (!(cache->flags & F_DHCP)) 659 { 660 *up = cache->hash_next; 661 if (cache->flags & F_BIGNAME) 662 { 663 cache->name.bname->next = big_free; 664 big_free = cache->name.bname; 665 } 666 cache->flags = 0; 667 } 668 else 669 up = &cache->hash_next; 670 } 671 672 if ((opts & OPT_NO_HOSTS) && !addn_hosts) 673 { 674 if (cache_size > 0) 675 syslog(LOG_INFO, _("cleared cache")); 676 return; 677 } 678 679 if (!(opts & OPT_NO_HOSTS)) 680 read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0); 681 while (addn_hosts) 682 { 683 read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index); 684 addn_hosts = addn_hosts->next; 685 } 686} 687 688void cache_unhash_dhcp(void) 689{ 690 struct crec *tmp, *cache, **up; 691 int i; 692 693 for (i=0; i<hash_size; i++) 694 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next) 695 if (cache->flags & F_DHCP) 696 *up = cache->hash_next; 697 else 698 up = &cache->hash_next; 699 700 /* prev field links all dhcp entries */ 701 for (cache = dhcp_inuse; cache; cache = tmp) 702 { 703 tmp = cache->prev; 704 cache->prev = dhcp_spare; 705 dhcp_spare = cache; 706 } 707 708 dhcp_inuse = NULL; 709} 710 711void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, 712 struct in_addr *host_address, time_t ttd) 713{ 714 struct crec *crec; 715 unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE; 716 717 if (!host_name) 718 return; 719 720 if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME))) 721 { 722 if (crec->flags & F_HOSTS) 723 { 724 if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr) 725 { 726 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4)); 727 syslog(LOG_WARNING, 728 _("not giving name %s to the DHCP lease of %s because " 729 "the name exists in %s with address %s"), 730 host_name, inet_ntoa(*host_address), 731 record_source(daemon->addn_hosts, crec->uid), daemon->namebuff); 732 } 733 return; 734 } 735 else if (!(crec->flags & F_DHCP)) 736 cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD)); 737 } 738 739 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4))) 740 { 741 if (crec->flags & F_NEG) 742 cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE); 743 else 744 /* avoid multiple reverse mappings */ 745 flags &= ~F_REVERSE; 746 } 747 748 if ((crec = dhcp_spare)) 749 dhcp_spare = dhcp_spare->prev; 750 else /* need new one */ 751 crec = malloc(sizeof(struct crec)); 752 753 if (crec) /* malloc may fail */ 754 { 755 crec->flags = flags; 756 if (ttd == 0) 757 crec->flags |= F_IMMORTAL; 758 else 759 crec->ttd = ttd; 760 crec->addr.addr.addr.addr4 = *host_address; 761 crec->name.namep = host_name; 762 crec->prev = dhcp_inuse; 763 dhcp_inuse = crec; 764 cache_hash(crec); 765 } 766} 767 768 769 770void dump_cache(struct daemon *daemon, time_t now) 771{ 772 syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."), 773 (unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted); 774 775 if ((daemon->options & (OPT_DEBUG | OPT_LOG)) && 776 (addrbuff || (addrbuff = malloc(ADDRSTRLEN)))) 777 { 778 struct crec *cache ; 779 int i; 780 syslog(LOG_DEBUG, "Host Address Flags Expires"); 781 782 for (i=0; i<hash_size; i++) 783 for (cache = hash_table[i]; cache; cache = cache->hash_next) 784 { 785 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD)) 786 addrbuff[0] = 0; 787 else if (cache->flags & F_CNAME) 788 { 789 addrbuff[0] = 0; 790 addrbuff[ADDRSTRLEN-1] = 0; 791 if (!is_outdated_cname_pointer(cache)) 792 strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN); 793 } 794#ifdef HAVE_IPV6 795 else if (cache->flags & F_IPV4) 796 inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN); 797 else if (cache->flags & F_IPV6) 798 inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN); 799#else 800 else 801 strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4)); 802#endif 803 syslog(LOG_DEBUG, 804#ifdef HAVE_BROKEN_RTC 805 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %lu", 806#else 807 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s", 808#endif 809 cache_get_name(cache), addrbuff, 810 cache->flags & F_IPV4 ? "4" : "", 811 cache->flags & F_IPV6 ? "6" : "", 812 cache->flags & F_CNAME ? "C" : "", 813 cache->flags & F_FORWARD ? "F" : " ", 814 cache->flags & F_REVERSE ? "R" : " ", 815 cache->flags & F_IMMORTAL ? "I" : " ", 816 cache->flags & F_DHCP ? "D" : " ", 817 cache->flags & F_NEG ? "N" : " ", 818 cache->flags & F_NXDOMAIN ? "X" : " ", 819 cache->flags & F_HOSTS ? "H" : " ", 820#ifdef HAVE_BROKEN_RTC 821 cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now) 822#else 823 cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)) 824#endif 825 ); 826 } 827 } 828} 829 830static char *record_source(struct hostsfile *addn_hosts, int index) 831{ 832 char *source = HOSTSFILE; 833 while (addn_hosts) 834 { 835 if (addn_hosts->index == index) 836 { 837 source = addn_hosts->fname; 838 break; 839 } 840 addn_hosts = addn_hosts->next; 841 } 842 843 return source; 844} 845 846void log_query(unsigned short flags, char *name, struct all_addr *addr, 847 unsigned short type, struct hostsfile *addn_hosts, int index) 848{ 849 char *source; 850 char *verb = "is"; 851 char types[20]; 852 853 if (!log_queries) 854 return; 855 856 if (flags & F_NEG) 857 { 858 if (flags & F_REVERSE) 859#ifdef HAVE_IPV6 860 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, 861 addr, name, MAXDNAME); 862#else 863 strcpy(name, inet_ntoa(addr->addr.addr4)); 864#endif 865 866 if (flags & F_NXDOMAIN) 867 strcpy(addrbuff, "<NXDOMAIN>"); 868 else 869 strcpy(addrbuff, "<NODATA>"); 870 871 if (flags & F_IPV4) 872 strcat(addrbuff, "-IPv4"); 873 else if (flags & F_IPV6) 874 strcat(addrbuff, "-IPv6"); 875 } 876 else if (flags & F_CNAME) 877 { 878 /* nasty abuse of IPV4 and IPV6 flags */ 879 if (flags & F_IPV4) 880 strcpy(addrbuff, "<MX>"); 881 else if (flags & F_IPV6) 882 strcpy(addrbuff, "<SRV>"); 883 else if (flags & F_NXDOMAIN) 884 strcpy(addrbuff, "<TXT>"); 885 else 886 strcpy(addrbuff, "<CNAME>"); 887 } 888 else 889#ifdef HAVE_IPV6 890 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6, 891 addr, addrbuff, ADDRSTRLEN); 892#else 893 strcpy(addrbuff, inet_ntoa(addr->addr.addr4)); 894#endif 895 896 if (flags & F_DHCP) 897 source = "DHCP"; 898 else if (flags & F_HOSTS) 899 source = record_source(addn_hosts, index); 900 else if (flags & F_CONFIG) 901 source = "config"; 902 else if (flags & F_UPSTREAM) 903 source = "reply"; 904 else if (flags & F_SERVER) 905 { 906 source = "forwarded"; 907 verb = "to"; 908 } 909 else if (flags & F_QUERY) 910 { 911 unsigned int i; 912 static const struct { 913 unsigned int type; 914 const char * const name; 915 } typestr[] = { 916 { 1, "A" }, 917 { 2, "NS" }, 918 { 5, "CNAME" }, 919 { 6, "SOA" }, 920 { 10, "NULL" }, 921 { 11, "WKS" }, 922 { 12, "PTR" }, 923 { 13, "HINFO" }, 924 { 15, "MX" }, 925 { 16, "TXT" }, 926 { 22, "NSAP" }, 927 { 23, "NSAP_PTR" }, 928 { 24, "SIG" }, 929 { 25, "KEY" }, 930 { 28, "AAAA" }, 931 { 33, "SRV" }, 932 { 36, "KX" }, 933 { 37, "CERT" }, 934 { 38, "A6" }, 935 { 39, "DNAME" }, 936 { 41, "OPT" }, 937 { 250, "TSIG" }, 938 { 251, "IXFR" }, 939 { 252, "AXFR" }, 940 { 253, "MAILB" }, 941 { 254, "MAILA" }, 942 { 255, "ANY" } 943 }; 944 945 if (type != 0) 946 { 947 sprintf(types, "query[type=%d]", type); 948 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) 949 if (typestr[i].type == type) 950 sprintf(types,"query[%s]", typestr[i].name); 951 } 952 source = types; 953 verb = "from"; 954 } 955 else 956 source = "cached"; 957 958 if (strlen(name) == 0) 959 name = "."; 960 961 if ((flags & F_FORWARD) | (flags & F_NEG)) 962 syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff); 963 else if (flags & F_REVERSE) 964 syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name); 965} 966 967