1/* dnsmasq is Copyright (c) 2000-2015 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#ifdef HAVE_AUTH 20 21static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u) 22{ 23 struct addrlist *subnet; 24 25 for (subnet = zone->subnet; subnet; subnet = subnet->next) 26 { 27 if (!(subnet->flags & ADDRLIST_IPV6)) 28 { 29 struct in_addr netmask, addr = addr_u->addr.addr4; 30 31 if (!(flag & F_IPV4)) 32 continue; 33 34 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen)); 35 36 if (is_same_net(addr, subnet->addr.addr.addr4, netmask)) 37 return subnet; 38 } 39#ifdef HAVE_IPV6 40 else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen)) 41 return subnet; 42#endif 43 44 } 45 return NULL; 46} 47 48static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) 49{ 50 /* No zones specified, no filter */ 51 if (!zone->subnet) 52 return 1; 53 54 return find_subnet(zone, flag, addr_u) != NULL; 55} 56 57int in_zone(struct auth_zone *zone, char *name, char **cut) 58{ 59 size_t namelen = strlen(name); 60 size_t domainlen = strlen(zone->domain); 61 62 if (cut) 63 *cut = NULL; 64 65 if (namelen >= domainlen && 66 hostname_isequal(zone->domain, &name[namelen - domainlen])) 67 { 68 69 if (namelen == domainlen) 70 return 1; 71 72 if (name[namelen - domainlen - 1] == '.') 73 { 74 if (cut) 75 *cut = &name[namelen - domainlen - 1]; 76 return 1; 77 } 78 } 79 80 return 0; 81} 82 83 84size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) 85{ 86 char *name = daemon->namebuff; 87 unsigned char *p, *ansp; 88 int qtype, qclass; 89 int nameoffset, axfroffset = 0; 90 int q, anscount = 0, authcount = 0; 91 struct crec *crecp; 92 int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; 93 struct auth_zone *zone = NULL; 94 struct addrlist *subnet = NULL; 95 char *cut; 96 struct mx_srv_record *rec, *move, **up; 97 struct txt_record *txt; 98 struct interface_name *intr; 99 struct naptr *na; 100 struct all_addr addr; 101 struct cname *a; 102 103 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) 104 return 0; 105 106 /* determine end of question section (we put answers there) */ 107 if (!(ansp = skip_questions(header, qlen))) 108 return 0; /* bad packet */ 109 110 /* now process each question, answers go in RRs after the question */ 111 p = (unsigned char *)(header+1); 112 113 for (q = ntohs(header->qdcount); q != 0; q--) 114 { 115 unsigned short flag = 0; 116 int found = 0; 117 118 /* save pointer to name for copying into answers */ 119 nameoffset = p - (unsigned char *)header; 120 121 /* now extract name as .-concatenated string into name */ 122 if (!extract_name(header, qlen, &p, name, 1, 4)) 123 return 0; /* bad packet */ 124 125 GETSHORT(qtype, p); 126 GETSHORT(qclass, p); 127 128 if (qclass != C_IN) 129 { 130 auth = 0; 131 continue; 132 } 133 134 if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) && 135 (flag = in_arpa_name_2_addr(name, &addr)) && 136 !local_query) 137 { 138 for (zone = daemon->auth_zones; zone; zone = zone->next) 139 if ((subnet = find_subnet(zone, flag, &addr))) 140 break; 141 142 if (!zone) 143 { 144 auth = 0; 145 continue; 146 } 147 else if (qtype == T_SOA) 148 soa = 1, found = 1; 149 else if (qtype == T_NS) 150 ns = 1, found = 1; 151 } 152 153 if (qtype == T_PTR && flag) 154 { 155 intr = NULL; 156 157 if (flag == F_IPV4) 158 for (intr = daemon->int_names; intr; intr = intr->next) 159 { 160 struct addrlist *addrlist; 161 162 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 163 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr) 164 break; 165 166 if (addrlist) 167 break; 168 else 169 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) 170 intr = intr->next; 171 } 172#ifdef HAVE_IPV6 173 else if (flag == F_IPV6) 174 for (intr = daemon->int_names; intr; intr = intr->next) 175 { 176 struct addrlist *addrlist; 177 178 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 179 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6)) 180 break; 181 182 if (addrlist) 183 break; 184 else 185 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) 186 intr = intr->next; 187 } 188#endif 189 190 if (intr) 191 { 192 if (local_query || in_zone(zone, intr->name, NULL)) 193 { 194 found = 1; 195 log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); 196 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 197 daemon->auth_ttl, NULL, 198 T_PTR, C_IN, "d", intr->name)) 199 anscount++; 200 } 201 } 202 203 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag))) 204 do { 205 strcpy(name, cache_get_name(crecp)); 206 207 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN)) 208 { 209 char *p = strchr(name, '.'); 210 if (p) 211 *p = 0; /* must be bare name */ 212 213 /* add external domain */ 214 if (zone) 215 { 216 strcat(name, "."); 217 strcat(name, zone->domain); 218 } 219 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid)); 220 found = 1; 221 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 222 daemon->auth_ttl, NULL, 223 T_PTR, C_IN, "d", name)) 224 anscount++; 225 } 226 else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL))) 227 { 228 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid)); 229 found = 1; 230 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 231 daemon->auth_ttl, NULL, 232 T_PTR, C_IN, "d", name)) 233 anscount++; 234 } 235 else 236 continue; 237 238 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag))); 239 240 if (found) 241 nxdomain = 0; 242 else 243 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL); 244 245 continue; 246 } 247 248 cname_restart: 249 if (found) 250 /* NS and SOA .arpa requests have set found above. */ 251 cut = NULL; 252 else 253 { 254 for (zone = daemon->auth_zones; zone; zone = zone->next) 255 if (in_zone(zone, name, &cut)) 256 break; 257 258 if (!zone) 259 { 260 auth = 0; 261 continue; 262 } 263 } 264 265 for (rec = daemon->mxnames; rec; rec = rec->next) 266 if (!rec->issrv && hostname_isequal(name, rec->name)) 267 { 268 nxdomain = 0; 269 270 if (qtype == T_MX) 271 { 272 found = 1; 273 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); 274 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 275 NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) 276 anscount++; 277 } 278 } 279 280 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) 281 if (rec->issrv && hostname_isequal(name, rec->name)) 282 { 283 nxdomain = 0; 284 285 if (qtype == T_SRV) 286 { 287 found = 1; 288 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); 289 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 290 NULL, T_SRV, C_IN, "sssd", 291 rec->priority, rec->weight, rec->srvport, rec->target)) 292 293 anscount++; 294 } 295 296 /* unlink first SRV record found */ 297 if (!move) 298 { 299 move = rec; 300 *up = rec->next; 301 } 302 else 303 up = &rec->next; 304 } 305 else 306 up = &rec->next; 307 308 /* put first SRV record back at the end. */ 309 if (move) 310 { 311 *up = move; 312 move->next = NULL; 313 } 314 315 for (txt = daemon->rr; txt; txt = txt->next) 316 if (hostname_isequal(name, txt->name)) 317 { 318 nxdomain = 0; 319 if (txt->class == qtype) 320 { 321 found = 1; 322 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); 323 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 324 NULL, txt->class, C_IN, "t", txt->len, txt->txt)) 325 anscount++; 326 } 327 } 328 329 for (txt = daemon->txt; txt; txt = txt->next) 330 if (txt->class == C_IN && hostname_isequal(name, txt->name)) 331 { 332 nxdomain = 0; 333 if (qtype == T_TXT) 334 { 335 found = 1; 336 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); 337 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 338 NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) 339 anscount++; 340 } 341 } 342 343 for (na = daemon->naptr; na; na = na->next) 344 if (hostname_isequal(name, na->name)) 345 { 346 nxdomain = 0; 347 if (qtype == T_NAPTR) 348 { 349 found = 1; 350 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>"); 351 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, 352 NULL, T_NAPTR, C_IN, "sszzzd", 353 na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) 354 anscount++; 355 } 356 } 357 358 if (qtype == T_A) 359 flag = F_IPV4; 360 361#ifdef HAVE_IPV6 362 if (qtype == T_AAAA) 363 flag = F_IPV6; 364#endif 365 366 for (intr = daemon->int_names; intr; intr = intr->next) 367 if (hostname_isequal(name, intr->name)) 368 { 369 struct addrlist *addrlist; 370 371 nxdomain = 0; 372 373 if (flag) 374 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 375 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && 376 (local_query || filter_zone(zone, flag, &addrlist->addr))) 377 { 378#ifdef HAVE_IPV6 379 if (addrlist->flags & ADDRLIST_REVONLY) 380 continue; 381#endif 382 found = 1; 383 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL); 384 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 385 daemon->auth_ttl, NULL, qtype, C_IN, 386 qtype == T_A ? "4" : "6", &addrlist->addr)) 387 anscount++; 388 } 389 } 390 391 for (a = daemon->cnames; a; a = a->next) 392 if (hostname_isequal(name, a->alias) ) 393 { 394 log_query(F_CONFIG | F_CNAME, name, NULL, NULL); 395 strcpy(name, a->target); 396 if (!strchr(name, '.')) 397 { 398 strcat(name, "."); 399 strcat(name, zone->domain); 400 } 401 found = 1; 402 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 403 daemon->auth_ttl, &nameoffset, 404 T_CNAME, C_IN, "d", name)) 405 anscount++; 406 407 goto cname_restart; 408 } 409 410 if (!cut) 411 { 412 nxdomain = 0; 413 414 if (qtype == T_SOA) 415 { 416 auth = soa = 1; /* inhibits auth section */ 417 found = 1; 418 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); 419 } 420 else if (qtype == T_AXFR) 421 { 422 struct iname *peers; 423 424 if (peer_addr->sa.sa_family == AF_INET) 425 peer_addr->in.sin_port = 0; 426#ifdef HAVE_IPV6 427 else 428 { 429 peer_addr->in6.sin6_port = 0; 430 peer_addr->in6.sin6_scope_id = 0; 431 } 432#endif 433 434 for (peers = daemon->auth_peers; peers; peers = peers->next) 435 if (sockaddr_isequal(peer_addr, &peers->addr)) 436 break; 437 438 /* Refuse all AXFR unless --auth-sec-servers is set */ 439 if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server) 440 { 441 if (peer_addr->sa.sa_family == AF_INET) 442 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); 443#ifdef HAVE_IPV6 444 else 445 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); 446#endif 447 448 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); 449 return 0; 450 } 451 452 auth = 1; 453 soa = 1; /* inhibits auth section */ 454 ns = 1; /* ensure we include NS records! */ 455 axfr = 1; 456 found = 1; 457 axfroffset = nameoffset; 458 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>"); 459 } 460 else if (qtype == T_NS) 461 { 462 auth = 1; 463 ns = 1; /* inhibits auth section */ 464 found = 1; 465 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); 466 } 467 } 468 469 if (!option_bool(OPT_DHCP_FQDN) && cut) 470 { 471 *cut = 0; /* remove domain part */ 472 473 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6))) 474 { 475 if (crecp->flags & F_DHCP) 476 do 477 { 478 nxdomain = 0; 479 if ((crecp->flags & flag) && 480 (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) 481 { 482 *cut = '.'; /* restore domain part */ 483 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); 484 *cut = 0; /* remove domain part */ 485 found = 1; 486 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 487 daemon->auth_ttl, NULL, qtype, C_IN, 488 qtype == T_A ? "4" : "6", &crecp->addr)) 489 anscount++; 490 } 491 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); 492 } 493 494 *cut = '.'; /* restore domain part */ 495 } 496 497 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6))) 498 { 499 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) 500 do 501 { 502 nxdomain = 0; 503 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) 504 { 505 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); 506 found = 1; 507 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 508 daemon->auth_ttl, NULL, qtype, C_IN, 509 qtype == T_A ? "4" : "6", &crecp->addr)) 510 anscount++; 511 } 512 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); 513 } 514 515 if (!found) 516 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); 517 518 } 519 520 /* Add auth section */ 521 if (auth && zone) 522 { 523 char *authname; 524 int newoffset, offset = 0; 525 526 if (!subnet) 527 authname = zone->domain; 528 else 529 { 530 /* handle NS and SOA for PTR records */ 531 532 authname = name; 533 534 if (!(subnet->flags & ADDRLIST_IPV6)) 535 { 536 in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8; 537 char *p = name; 538 539 if (subnet->prefixlen >= 24) 540 p += sprintf(p, "%d.", a & 0xff); 541 a = a >> 8; 542 if (subnet->prefixlen >= 16 ) 543 p += sprintf(p, "%d.", a & 0xff); 544 a = a >> 8; 545 p += sprintf(p, "%d.in-addr.arpa", a & 0xff); 546 547 } 548#ifdef HAVE_IPV6 549 else 550 { 551 char *p = name; 552 int i; 553 554 for (i = subnet->prefixlen-1; i >= 0; i -= 4) 555 { 556 int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3]; 557 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); 558 } 559 p += sprintf(p, "ip6.arpa"); 560 561 } 562#endif 563 } 564 565 /* handle NS and SOA in auth section or for explicit queries */ 566 newoffset = ansp - (unsigned char *)header; 567 if (((anscount == 0 && !ns) || soa) && 568 add_resource_record(header, limit, &trunc, 0, &ansp, 569 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll", 570 authname, daemon->authserver, daemon->hostmaster, 571 daemon->soa_sn, daemon->soa_refresh, 572 daemon->soa_retry, daemon->soa_expiry, 573 daemon->auth_ttl)) 574 { 575 offset = newoffset; 576 if (soa) 577 anscount++; 578 else 579 authcount++; 580 } 581 582 if (anscount != 0 || ns) 583 { 584 struct name_list *secondary; 585 586 newoffset = ansp - (unsigned char *)header; 587 if (add_resource_record(header, limit, &trunc, -offset, &ansp, 588 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) 589 { 590 if (offset == 0) 591 offset = newoffset; 592 if (ns) 593 anscount++; 594 else 595 authcount++; 596 } 597 598 if (!subnet) 599 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next) 600 if (add_resource_record(header, limit, &trunc, offset, &ansp, 601 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name)) 602 { 603 if (ns) 604 anscount++; 605 else 606 authcount++; 607 } 608 } 609 610 if (axfr) 611 { 612 for (rec = daemon->mxnames; rec; rec = rec->next) 613 if (in_zone(zone, rec->name, &cut)) 614 { 615 if (cut) 616 *cut = 0; 617 618 if (rec->issrv) 619 { 620 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 621 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL, 622 rec->priority, rec->weight, rec->srvport, rec->target)) 623 624 anscount++; 625 } 626 else 627 { 628 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 629 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target)) 630 anscount++; 631 } 632 633 /* restore config data */ 634 if (cut) 635 *cut = '.'; 636 } 637 638 for (txt = daemon->rr; txt; txt = txt->next) 639 if (in_zone(zone, txt->name, &cut)) 640 { 641 if (cut) 642 *cut = 0; 643 644 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 645 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt)) 646 anscount++; 647 648 /* restore config data */ 649 if (cut) 650 *cut = '.'; 651 } 652 653 for (txt = daemon->txt; txt; txt = txt->next) 654 if (txt->class == C_IN && in_zone(zone, txt->name, &cut)) 655 { 656 if (cut) 657 *cut = 0; 658 659 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 660 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt)) 661 anscount++; 662 663 /* restore config data */ 664 if (cut) 665 *cut = '.'; 666 } 667 668 for (na = daemon->naptr; na; na = na->next) 669 if (in_zone(zone, na->name, &cut)) 670 { 671 if (cut) 672 *cut = 0; 673 674 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, 675 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL, 676 na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) 677 anscount++; 678 679 /* restore config data */ 680 if (cut) 681 *cut = '.'; 682 } 683 684 for (intr = daemon->int_names; intr; intr = intr->next) 685 if (in_zone(zone, intr->name, &cut)) 686 { 687 struct addrlist *addrlist; 688 689 if (cut) 690 *cut = 0; 691 692 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 693 if (!(addrlist->flags & ADDRLIST_IPV6) && 694 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) && 695 add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 696 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) 697 anscount++; 698 699#ifdef HAVE_IPV6 700 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 701 if ((addrlist->flags & ADDRLIST_IPV6) && 702 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && 703 add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 704 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) 705 anscount++; 706#endif 707 708 /* restore config data */ 709 if (cut) 710 *cut = '.'; 711 } 712 713 for (a = daemon->cnames; a; a = a->next) 714 if (in_zone(zone, a->alias, &cut)) 715 { 716 strcpy(name, a->target); 717 if (!strchr(name, '.')) 718 { 719 strcat(name, "."); 720 strcat(name, zone->domain); 721 } 722 723 if (cut) 724 *cut = 0; 725 726 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 727 daemon->auth_ttl, NULL, 728 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name)) 729 anscount++; 730 } 731 732 cache_enumerate(1); 733 while ((crecp = cache_enumerate(0))) 734 { 735 if ((crecp->flags & (F_IPV4 | F_IPV6)) && 736 !(crecp->flags & (F_NEG | F_NXDOMAIN)) && 737 (crecp->flags & F_FORWARD)) 738 { 739 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN)) 740 { 741 char *cache_name = cache_get_name(crecp); 742 if (!strchr(cache_name, '.') && 743 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) 744 { 745 qtype = T_A; 746#ifdef HAVE_IPV6 747 if (crecp->flags & F_IPV6) 748 qtype = T_AAAA; 749#endif 750 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 751 daemon->auth_ttl, NULL, qtype, C_IN, 752 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) 753 anscount++; 754 } 755 } 756 757 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) 758 { 759 strcpy(name, cache_get_name(crecp)); 760 if (in_zone(zone, name, &cut) && 761 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) 762 { 763 qtype = T_A; 764#ifdef HAVE_IPV6 765 if (crecp->flags & F_IPV6) 766 qtype = T_AAAA; 767#endif 768 if (cut) 769 *cut = 0; 770 771 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 772 daemon->auth_ttl, NULL, qtype, C_IN, 773 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) 774 anscount++; 775 } 776 } 777 } 778 } 779 780 /* repeat SOA as last record */ 781 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp, 782 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll", 783 daemon->authserver, daemon->hostmaster, 784 daemon->soa_sn, daemon->soa_refresh, 785 daemon->soa_retry, daemon->soa_expiry, 786 daemon->auth_ttl)) 787 anscount++; 788 789 } 790 791 } 792 793 /* done all questions, set up header and return length of result */ 794 /* clear authoritative and truncated flags, set QR flag */ 795 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR; 796 797 if (local_query) 798 { 799 /* set RA flag */ 800 header->hb4 |= HB4_RA; 801 } 802 else 803 { 804 /* clear RA flag */ 805 header->hb4 &= ~HB4_RA; 806 } 807 808 /* authoritive */ 809 if (auth) 810 header->hb3 |= HB3_AA; 811 812 /* truncation */ 813 if (trunc) 814 header->hb3 |= HB3_TC; 815 816 if ((auth || local_query) && nxdomain) 817 SET_RCODE(header, NXDOMAIN); 818 else 819 SET_RCODE(header, NOERROR); /* no error */ 820 header->ancount = htons(anscount); 821 header->nscount = htons(authcount); 822 header->arcount = htons(0); 823 return ansp - (unsigned char *)header; 824} 825 826#endif 827 828 829 830