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