Annotation of embedaddon/dnsmasq/src/rfc1035.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:
! 20: #define CHECK_LEN(header, pp, plen, len) \
! 21: ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
! 22:
! 23: #define ADD_RDLEN(header, pp, plen, len) \
! 24: (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
! 25:
! 26: int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
! 27: char *name, int isExtract, int extrabytes)
! 28: {
! 29: unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
! 30: unsigned int j, l, hops = 0;
! 31: int retvalue = 1;
! 32:
! 33: if (isExtract)
! 34: *cp = 0;
! 35:
! 36: while (1)
! 37: {
! 38: unsigned int label_type;
! 39:
! 40: if (!CHECK_LEN(header, p, plen, 1))
! 41: return 0;
! 42:
! 43: if ((l = *p++) == 0)
! 44: /* end marker */
! 45: {
! 46: /* check that there are the correct no of bytes after the name */
! 47: if (!CHECK_LEN(header, p, plen, extrabytes))
! 48: return 0;
! 49:
! 50: if (isExtract)
! 51: {
! 52: if (cp != (unsigned char *)name)
! 53: cp--;
! 54: *cp = 0; /* terminate: lose final period */
! 55: }
! 56: else if (*cp != 0)
! 57: retvalue = 2;
! 58:
! 59: if (p1) /* we jumped via compression */
! 60: *pp = p1;
! 61: else
! 62: *pp = p;
! 63:
! 64: return retvalue;
! 65: }
! 66:
! 67: label_type = l & 0xc0;
! 68:
! 69: if (label_type == 0xc0) /* pointer */
! 70: {
! 71: if (!CHECK_LEN(header, p, plen, 1))
! 72: return 0;
! 73:
! 74: /* get offset */
! 75: l = (l&0x3f) << 8;
! 76: l |= *p++;
! 77:
! 78: if (!p1) /* first jump, save location to go back to */
! 79: p1 = p;
! 80:
! 81: hops++; /* break malicious infinite loops */
! 82: if (hops > 255)
! 83: return 0;
! 84:
! 85: p = l + (unsigned char *)header;
! 86: }
! 87: else if (label_type == 0x80)
! 88: return 0; /* reserved */
! 89: else if (label_type == 0x40)
! 90: { /* ELT */
! 91: unsigned int count, digs;
! 92:
! 93: if ((l & 0x3f) != 1)
! 94: return 0; /* we only understand bitstrings */
! 95:
! 96: if (!isExtract)
! 97: return 0; /* Cannot compare bitsrings */
! 98:
! 99: count = *p++;
! 100: if (count == 0)
! 101: count = 256;
! 102: digs = ((count-1)>>2)+1;
! 103:
! 104: /* output is \[x<hex>/siz]. which is digs+9 chars */
! 105: if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
! 106: return 0;
! 107: if (!CHECK_LEN(header, p, plen, (count-1)>>3))
! 108: return 0;
! 109:
! 110: *cp++ = '\\';
! 111: *cp++ = '[';
! 112: *cp++ = 'x';
! 113: for (j=0; j<digs; j++)
! 114: {
! 115: unsigned int dig;
! 116: if (j%2 == 0)
! 117: dig = *p >> 4;
! 118: else
! 119: dig = *p++ & 0x0f;
! 120:
! 121: *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
! 122: }
! 123: cp += sprintf((char *)cp, "/%d]", count);
! 124: /* do this here to overwrite the zero char from sprintf */
! 125: *cp++ = '.';
! 126: }
! 127: else
! 128: { /* label_type = 0 -> label. */
! 129: if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
! 130: return 0;
! 131: if (!CHECK_LEN(header, p, plen, l))
! 132: return 0;
! 133:
! 134: for(j=0; j<l; j++, p++)
! 135: if (isExtract)
! 136: {
! 137: unsigned char c = *p;
! 138: if (isascii(c) && !iscntrl(c) && c != '.')
! 139: *cp++ = *p;
! 140: else
! 141: return 0;
! 142: }
! 143: else
! 144: {
! 145: unsigned char c1 = *cp, c2 = *p;
! 146:
! 147: if (c1 == 0)
! 148: retvalue = 2;
! 149: else
! 150: {
! 151: cp++;
! 152: if (c1 >= 'A' && c1 <= 'Z')
! 153: c1 += 'a' - 'A';
! 154: if (c2 >= 'A' && c2 <= 'Z')
! 155: c2 += 'a' - 'A';
! 156:
! 157: if (c1 != c2)
! 158: retvalue = 2;
! 159: }
! 160: }
! 161:
! 162: if (isExtract)
! 163: *cp++ = '.';
! 164: else if (*cp != 0 && *cp++ != '.')
! 165: retvalue = 2;
! 166: }
! 167: }
! 168: }
! 169:
! 170: /* Max size of input string (for IPv6) is 75 chars.) */
! 171: #define MAXARPANAME 75
! 172: int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
! 173: {
! 174: int j;
! 175: char name[MAXARPANAME+1], *cp1;
! 176: unsigned char *addr = (unsigned char *)addrp;
! 177: char *lastchunk = NULL, *penchunk = NULL;
! 178:
! 179: if (strlen(namein) > MAXARPANAME)
! 180: return 0;
! 181:
! 182: memset(addrp, 0, sizeof(struct all_addr));
! 183:
! 184: /* turn name into a series of asciiz strings */
! 185: /* j counts no of labels */
! 186: for(j = 1,cp1 = name; *namein; cp1++, namein++)
! 187: if (*namein == '.')
! 188: {
! 189: penchunk = lastchunk;
! 190: lastchunk = cp1 + 1;
! 191: *cp1 = 0;
! 192: j++;
! 193: }
! 194: else
! 195: *cp1 = *namein;
! 196:
! 197: *cp1 = 0;
! 198:
! 199: if (j<3)
! 200: return 0;
! 201:
! 202: if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
! 203: {
! 204: /* IP v4 */
! 205: /* address arives as a name of the form
! 206: www.xxx.yyy.zzz.in-addr.arpa
! 207: some of the low order address octets might be missing
! 208: and should be set to zero. */
! 209: for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
! 210: {
! 211: /* check for digits only (weeds out things like
! 212: 50.0/24.67.28.64.in-addr.arpa which are used
! 213: as CNAME targets according to RFC 2317 */
! 214: char *cp;
! 215: for (cp = cp1; *cp; cp++)
! 216: if (!isdigit((unsigned char)*cp))
! 217: return 0;
! 218:
! 219: addr[3] = addr[2];
! 220: addr[2] = addr[1];
! 221: addr[1] = addr[0];
! 222: addr[0] = atoi(cp1);
! 223: }
! 224:
! 225: return F_IPV4;
! 226: }
! 227: #ifdef HAVE_IPV6
! 228: else if (hostname_isequal(penchunk, "ip6") &&
! 229: (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
! 230: {
! 231: /* IP v6:
! 232: Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
! 233: or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
! 234:
! 235: Note that most of these the various reprentations are obsolete and
! 236: left-over from the many DNS-for-IPv6 wars. We support all the formats
! 237: that we can since there is no reason not to.
! 238: */
! 239:
! 240: if (*name == '\\' && *(name+1) == '[' &&
! 241: (*(name+2) == 'x' || *(name+2) == 'X'))
! 242: {
! 243: for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
! 244: {
! 245: char xdig[2];
! 246: xdig[0] = *cp1;
! 247: xdig[1] = 0;
! 248: if (j%2)
! 249: addr[j/2] |= strtol(xdig, NULL, 16);
! 250: else
! 251: addr[j/2] = strtol(xdig, NULL, 16) << 4;
! 252: }
! 253:
! 254: if (*cp1 == '/' && j == 32)
! 255: return F_IPV6;
! 256: }
! 257: else
! 258: {
! 259: for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
! 260: {
! 261: if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
! 262: return 0;
! 263:
! 264: for (j = sizeof(struct all_addr)-1; j>0; j--)
! 265: addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
! 266: addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
! 267: }
! 268:
! 269: return F_IPV6;
! 270: }
! 271: }
! 272: #endif
! 273:
! 274: return 0;
! 275: }
! 276:
! 277: static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
! 278: {
! 279: while(1)
! 280: {
! 281: unsigned int label_type;
! 282:
! 283: if (!CHECK_LEN(header, ansp, plen, 1))
! 284: return NULL;
! 285:
! 286: label_type = (*ansp) & 0xc0;
! 287:
! 288: if (label_type == 0xc0)
! 289: {
! 290: /* pointer for compression. */
! 291: ansp += 2;
! 292: break;
! 293: }
! 294: else if (label_type == 0x80)
! 295: return NULL; /* reserved */
! 296: else if (label_type == 0x40)
! 297: {
! 298: /* Extended label type */
! 299: unsigned int count;
! 300:
! 301: if (!CHECK_LEN(header, ansp, plen, 2))
! 302: return NULL;
! 303:
! 304: if (((*ansp++) & 0x3f) != 1)
! 305: return NULL; /* we only understand bitstrings */
! 306:
! 307: count = *(ansp++); /* Bits in bitstring */
! 308:
! 309: if (count == 0) /* count == 0 means 256 bits */
! 310: ansp += 32;
! 311: else
! 312: ansp += ((count-1)>>3)+1;
! 313: }
! 314: else
! 315: { /* label type == 0 Bottom six bits is length */
! 316: unsigned int len = (*ansp++) & 0x3f;
! 317:
! 318: if (!ADD_RDLEN(header, ansp, plen, len))
! 319: return NULL;
! 320:
! 321: if (len == 0)
! 322: break; /* zero length label marks the end. */
! 323: }
! 324: }
! 325:
! 326: if (!CHECK_LEN(header, ansp, plen, extrabytes))
! 327: return NULL;
! 328:
! 329: return ansp;
! 330: }
! 331:
! 332: unsigned char *skip_questions(struct dns_header *header, size_t plen)
! 333: {
! 334: int q;
! 335: unsigned char *ansp = (unsigned char *)(header+1);
! 336:
! 337: for (q = ntohs(header->qdcount); q != 0; q--)
! 338: {
! 339: if (!(ansp = skip_name(ansp, header, plen, 4)))
! 340: return NULL;
! 341: ansp += 4; /* class and type */
! 342: }
! 343:
! 344: return ansp;
! 345: }
! 346:
! 347: static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
! 348: {
! 349: int i, rdlen;
! 350:
! 351: for (i = 0; i < count; i++)
! 352: {
! 353: if (!(ansp = skip_name(ansp, header, plen, 10)))
! 354: return NULL;
! 355: ansp += 8; /* type, class, TTL */
! 356: GETSHORT(rdlen, ansp);
! 357: if (!ADD_RDLEN(header, ansp, plen, rdlen))
! 358: return NULL;
! 359: }
! 360:
! 361: return ansp;
! 362: }
! 363:
! 364: /* CRC the question section. This is used to safely detect query
! 365: retransmision and to detect answers to questions we didn't ask, which
! 366: might be poisoning attacks. Note that we decode the name rather
! 367: than CRC the raw bytes, since replies might be compressed differently.
! 368: We ignore case in the names for the same reason. Return all-ones
! 369: if there is not question section. */
! 370: unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
! 371: {
! 372: int q;
! 373: unsigned int crc = 0xffffffff;
! 374: unsigned char *p1, *p = (unsigned char *)(header+1);
! 375:
! 376: for (q = ntohs(header->qdcount); q != 0; q--)
! 377: {
! 378: if (!extract_name(header, plen, &p, name, 1, 4))
! 379: return crc; /* bad packet */
! 380:
! 381: for (p1 = (unsigned char *)name; *p1; p1++)
! 382: {
! 383: int i = 8;
! 384: char c = *p1;
! 385:
! 386: if (c >= 'A' && c <= 'Z')
! 387: c += 'a' - 'A';
! 388:
! 389: crc ^= c << 24;
! 390: while (i--)
! 391: crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
! 392: }
! 393:
! 394: /* CRC the class and type as well */
! 395: for (p1 = p; p1 < p+4; p1++)
! 396: {
! 397: int i = 8;
! 398: crc ^= *p1 << 24;
! 399: while (i--)
! 400: crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
! 401: }
! 402:
! 403: p += 4;
! 404: if (!CHECK_LEN(header, p, plen, 0))
! 405: return crc; /* bad packet */
! 406: }
! 407:
! 408: return crc;
! 409: }
! 410:
! 411:
! 412: size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
! 413: {
! 414: unsigned char *ansp = skip_questions(header, plen);
! 415:
! 416: /* if packet is malformed, just return as-is. */
! 417: if (!ansp)
! 418: return plen;
! 419:
! 420: if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
! 421: header, plen)))
! 422: return plen;
! 423:
! 424: /* restore pseudoheader */
! 425: if (pheader && ntohs(header->arcount) == 0)
! 426: {
! 427: /* must use memmove, may overlap */
! 428: memmove(ansp, pheader, hlen);
! 429: header->arcount = htons(1);
! 430: ansp += hlen;
! 431: }
! 432:
! 433: return ansp - (unsigned char *)header;
! 434: }
! 435:
! 436: unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
! 437: {
! 438: /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
! 439: also return length of pseudoheader in *len and pointer to the UDP size in *p
! 440: Finally, check to see if a packet is signed. If it is we cannot change a single bit before
! 441: forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
! 442:
! 443: int i, arcount = ntohs(header->arcount);
! 444: unsigned char *ansp = (unsigned char *)(header+1);
! 445: unsigned short rdlen, type, class;
! 446: unsigned char *ret = NULL;
! 447:
! 448: if (is_sign)
! 449: {
! 450: *is_sign = 0;
! 451:
! 452: if (OPCODE(header) == QUERY)
! 453: {
! 454: for (i = ntohs(header->qdcount); i != 0; i--)
! 455: {
! 456: if (!(ansp = skip_name(ansp, header, plen, 4)))
! 457: return NULL;
! 458:
! 459: GETSHORT(type, ansp);
! 460: GETSHORT(class, ansp);
! 461:
! 462: if (class == C_IN && type == T_TKEY)
! 463: *is_sign = 1;
! 464: }
! 465: }
! 466: }
! 467: else
! 468: {
! 469: if (!(ansp = skip_questions(header, plen)))
! 470: return NULL;
! 471: }
! 472:
! 473: if (arcount == 0)
! 474: return NULL;
! 475:
! 476: if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
! 477: return NULL;
! 478:
! 479: for (i = 0; i < arcount; i++)
! 480: {
! 481: unsigned char *save, *start = ansp;
! 482: if (!(ansp = skip_name(ansp, header, plen, 10)))
! 483: return NULL;
! 484:
! 485: GETSHORT(type, ansp);
! 486: save = ansp;
! 487: GETSHORT(class, ansp);
! 488: ansp += 4; /* TTL */
! 489: GETSHORT(rdlen, ansp);
! 490: if (!ADD_RDLEN(header, ansp, plen, rdlen))
! 491: return NULL;
! 492: if (type == T_OPT)
! 493: {
! 494: if (len)
! 495: *len = ansp - start;
! 496: if (p)
! 497: *p = save;
! 498: ret = start;
! 499: }
! 500: else if (is_sign &&
! 501: i == arcount - 1 &&
! 502: class == C_ANY &&
! 503: (type == T_SIG || type == T_TSIG))
! 504: *is_sign = 1;
! 505: }
! 506:
! 507: return ret;
! 508: }
! 509:
! 510: struct macparm {
! 511: unsigned char *limit;
! 512: struct dns_header *header;
! 513: size_t plen;
! 514: union mysockaddr *l3;
! 515: };
! 516:
! 517: static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
! 518: {
! 519: struct macparm *parm = parmv;
! 520: int match = 0;
! 521: unsigned short rdlen;
! 522: struct dns_header *header = parm->header;
! 523: unsigned char *lenp, *datap, *p;
! 524:
! 525: if (family == parm->l3->sa.sa_family)
! 526: {
! 527: if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
! 528: match = 1;
! 529: #ifdef HAVE_IPV6
! 530: else
! 531: if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
! 532: match = 1;
! 533: #endif
! 534: }
! 535:
! 536: if (!match)
! 537: return 1; /* continue */
! 538:
! 539: if (ntohs(header->arcount) == 0)
! 540: {
! 541: /* We are adding the pseudoheader */
! 542: if (!(p = skip_questions(header, parm->plen)) ||
! 543: !(p = skip_section(p,
! 544: ntohs(header->ancount) + ntohs(header->nscount),
! 545: header, parm->plen)))
! 546: return 0;
! 547: *p++ = 0; /* empty name */
! 548: PUTSHORT(T_OPT, p);
! 549: PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
! 550: PUTLONG(0, p); /* extended RCODE */
! 551: lenp = p;
! 552: PUTSHORT(0, p); /* RDLEN */
! 553: rdlen = 0;
! 554: if (((ssize_t)maclen) > (parm->limit - (p + 4)))
! 555: return 0; /* Too big */
! 556: header->arcount = htons(1);
! 557: datap = p;
! 558: }
! 559: else
! 560: {
! 561: int i, is_sign;
! 562: unsigned short code, len;
! 563:
! 564: if (ntohs(header->arcount) != 1 ||
! 565: !(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
! 566: is_sign ||
! 567: (!(p = skip_name(p, header, parm->plen, 10))))
! 568: return 0;
! 569:
! 570: p += 8; /* skip UDP length and RCODE */
! 571:
! 572: lenp = p;
! 573: GETSHORT(rdlen, p);
! 574: if (!CHECK_LEN(header, p, parm->plen, rdlen))
! 575: return 0; /* bad packet */
! 576: datap = p;
! 577:
! 578: /* check if option already there */
! 579: for (i = 0; i + 4 < rdlen; i += len + 4)
! 580: {
! 581: GETSHORT(code, p);
! 582: GETSHORT(len, p);
! 583: if (code == EDNS0_OPTION_MAC)
! 584: return 0;
! 585: p += len;
! 586: }
! 587:
! 588: if (((ssize_t)maclen) > (parm->limit - (p + 4)))
! 589: return 0; /* Too big */
! 590: }
! 591:
! 592: PUTSHORT(EDNS0_OPTION_MAC, p);
! 593: PUTSHORT(maclen, p);
! 594: memcpy(p, mac, maclen);
! 595: p += maclen;
! 596:
! 597: PUTSHORT(p - datap, lenp);
! 598: parm->plen = p - (unsigned char *)header;
! 599:
! 600: return 0; /* done */
! 601: }
! 602:
! 603:
! 604: size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
! 605: {
! 606: struct macparm parm;
! 607:
! 608: /* Must have an existing pseudoheader as the only ar-record,
! 609: or have no ar-records. Must also not be signed */
! 610:
! 611: if (ntohs(header->arcount) > 1)
! 612: return plen;
! 613:
! 614: parm.header = header;
! 615: parm.limit = (unsigned char *)limit;
! 616: parm.plen = plen;
! 617: parm.l3 = l3;
! 618:
! 619: iface_enumerate(AF_UNSPEC, &parm, filter_mac);
! 620:
! 621: return parm.plen;
! 622: }
! 623:
! 624:
! 625: /* is addr in the non-globally-routed IP space? */
! 626: static int private_net(struct in_addr addr, int ban_localhost)
! 627: {
! 628: in_addr_t ip_addr = ntohl(addr.s_addr);
! 629:
! 630: return
! 631: (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
! 632: ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
! 633: ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
! 634: ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
! 635: ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
! 636: }
! 637:
! 638: static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
! 639: {
! 640: int i, qtype, qclass, rdlen;
! 641:
! 642: for (i = count; i != 0; i--)
! 643: {
! 644: if (name && option_bool(OPT_LOG))
! 645: {
! 646: if (!extract_name(header, qlen, &p, name, 1, 10))
! 647: return 0;
! 648: }
! 649: else if (!(p = skip_name(p, header, qlen, 10)))
! 650: return 0; /* bad packet */
! 651:
! 652: GETSHORT(qtype, p);
! 653: GETSHORT(qclass, p);
! 654: p += 4; /* ttl */
! 655: GETSHORT(rdlen, p);
! 656:
! 657: if (qclass == C_IN && qtype == T_A)
! 658: {
! 659: struct doctor *doctor;
! 660: struct in_addr addr;
! 661:
! 662: if (!CHECK_LEN(header, p, qlen, INADDRSZ))
! 663: return 0;
! 664:
! 665: /* alignment */
! 666: memcpy(&addr, p, INADDRSZ);
! 667:
! 668: for (doctor = daemon->doctors; doctor; doctor = doctor->next)
! 669: {
! 670: if (doctor->end.s_addr == 0)
! 671: {
! 672: if (!is_same_net(doctor->in, addr, doctor->mask))
! 673: continue;
! 674: }
! 675: else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
! 676: ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
! 677: continue;
! 678:
! 679: addr.s_addr &= ~doctor->mask.s_addr;
! 680: addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
! 681: /* Since we munged the data, the server it came from is no longer authoritative */
! 682: header->hb3 &= ~HB3_AA;
! 683: memcpy(p, &addr, INADDRSZ);
! 684: break;
! 685: }
! 686: }
! 687: else if (qtype == T_TXT && name && option_bool(OPT_LOG))
! 688: {
! 689: unsigned char *p1 = p;
! 690: if (!CHECK_LEN(header, p1, qlen, rdlen))
! 691: return 0;
! 692: while ((p1 - p) < rdlen)
! 693: {
! 694: unsigned int i, len = *p1;
! 695: unsigned char *p2 = p1;
! 696: /* make counted string zero-term and sanitise */
! 697: for (i = 0; i < len; i++)
! 698: {
! 699: if (!isprint((int)*(p2+1)))
! 700: break;
! 701:
! 702: *p2 = *(p2+1);
! 703: p2++;
! 704: }
! 705: *p2 = 0;
! 706: my_syslog(LOG_INFO, "reply %s is %s", name, p1);
! 707: /* restore */
! 708: memmove(p1 + 1, p1, i);
! 709: *p1 = len;
! 710: p1 += len+1;
! 711: }
! 712: }
! 713:
! 714: if (!ADD_RDLEN(header, p, qlen, rdlen))
! 715: return 0; /* bad packet */
! 716: }
! 717:
! 718: return p;
! 719: }
! 720:
! 721: static int find_soa(struct dns_header *header, size_t qlen, char *name)
! 722: {
! 723: unsigned char *p;
! 724: int qtype, qclass, rdlen;
! 725: unsigned long ttl, minttl = ULONG_MAX;
! 726: int i, found_soa = 0;
! 727:
! 728: /* first move to NS section and find TTL from any SOA section */
! 729: if (!(p = skip_questions(header, qlen)) ||
! 730: !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name)))
! 731: return 0; /* bad packet */
! 732:
! 733: for (i = ntohs(header->nscount); i != 0; i--)
! 734: {
! 735: if (!(p = skip_name(p, header, qlen, 10)))
! 736: return 0; /* bad packet */
! 737:
! 738: GETSHORT(qtype, p);
! 739: GETSHORT(qclass, p);
! 740: GETLONG(ttl, p);
! 741: GETSHORT(rdlen, p);
! 742:
! 743: if ((qclass == C_IN) && (qtype == T_SOA))
! 744: {
! 745: found_soa = 1;
! 746: if (ttl < minttl)
! 747: minttl = ttl;
! 748:
! 749: /* MNAME */
! 750: if (!(p = skip_name(p, header, qlen, 0)))
! 751: return 0;
! 752: /* RNAME */
! 753: if (!(p = skip_name(p, header, qlen, 20)))
! 754: return 0;
! 755: p += 16; /* SERIAL REFRESH RETRY EXPIRE */
! 756:
! 757: GETLONG(ttl, p); /* minTTL */
! 758: if (ttl < minttl)
! 759: minttl = ttl;
! 760: }
! 761: else if (!ADD_RDLEN(header, p, qlen, rdlen))
! 762: return 0; /* bad packet */
! 763: }
! 764:
! 765: /* rewrite addresses in additioal section too */
! 766: if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL))
! 767: return 0;
! 768:
! 769: if (!found_soa)
! 770: minttl = daemon->neg_ttl;
! 771:
! 772: return minttl;
! 773: }
! 774:
! 775: /* Note that the following code can create CNAME chains that don't point to a real record,
! 776: either because of lack of memory, or lack of SOA records. These are treated by the cache code as
! 777: expired and cleaned out that way.
! 778: Return 1 if we reject an address because it look like part of dns-rebinding attack. */
! 779: int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
! 780: char **ipsets, int is_sign, int check_rebind, int checking_disabled)
! 781: {
! 782: unsigned char *p, *p1, *endrr, *namep;
! 783: int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
! 784: unsigned long ttl = 0;
! 785: struct all_addr addr;
! 786: #ifdef HAVE_IPSET
! 787: char **ipsets_cur;
! 788: #else
! 789: (void)ipsets; /* unused */
! 790: #endif
! 791:
! 792: cache_start_insert();
! 793:
! 794: /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
! 795: if (daemon->doctors || option_bool(OPT_LOG))
! 796: {
! 797: searched_soa = 1;
! 798: ttl = find_soa(header, qlen, name);
! 799: }
! 800:
! 801: /* go through the questions. */
! 802: p = (unsigned char *)(header+1);
! 803:
! 804: for (i = ntohs(header->qdcount); i != 0; i--)
! 805: {
! 806: int found = 0, cname_count = 5;
! 807: struct crec *cpp = NULL;
! 808: int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
! 809: unsigned long cttl = ULONG_MAX, attl;
! 810:
! 811: namep = p;
! 812: if (!extract_name(header, qlen, &p, name, 1, 4))
! 813: return 0; /* bad packet */
! 814:
! 815: GETSHORT(qtype, p);
! 816: GETSHORT(qclass, p);
! 817:
! 818: if (qclass != C_IN)
! 819: continue;
! 820:
! 821: /* PTRs: we chase CNAMEs here, since we have no way to
! 822: represent them in the cache. */
! 823: if (qtype == T_PTR)
! 824: {
! 825: int name_encoding = in_arpa_name_2_addr(name, &addr);
! 826:
! 827: if (!name_encoding)
! 828: continue;
! 829:
! 830: if (!(flags & F_NXDOMAIN))
! 831: {
! 832: cname_loop:
! 833: if (!(p1 = skip_questions(header, qlen)))
! 834: return 0;
! 835:
! 836: for (j = ntohs(header->ancount); j != 0; j--)
! 837: {
! 838: unsigned char *tmp = namep;
! 839: /* the loop body overwrites the original name, so get it back here. */
! 840: if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
! 841: !(res = extract_name(header, qlen, &p1, name, 0, 10)))
! 842: return 0; /* bad packet */
! 843:
! 844: GETSHORT(aqtype, p1);
! 845: GETSHORT(aqclass, p1);
! 846: GETLONG(attl, p1);
! 847: if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
! 848: {
! 849: (p1) -= 4;
! 850: PUTLONG(daemon->max_ttl, p1);
! 851: }
! 852: GETSHORT(ardlen, p1);
! 853: endrr = p1+ardlen;
! 854:
! 855: /* TTL of record is minimum of CNAMES and PTR */
! 856: if (attl < cttl)
! 857: cttl = attl;
! 858:
! 859: if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
! 860: {
! 861: if (!extract_name(header, qlen, &p1, name, 1, 0))
! 862: return 0;
! 863:
! 864: if (aqtype == T_CNAME)
! 865: {
! 866: if (!cname_count--)
! 867: return 0; /* looped CNAMES */
! 868: goto cname_loop;
! 869: }
! 870:
! 871: cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
! 872: found = 1;
! 873: }
! 874:
! 875: p1 = endrr;
! 876: if (!CHECK_LEN(header, p1, qlen, 0))
! 877: return 0; /* bad packet */
! 878: }
! 879: }
! 880:
! 881: if (!found && !option_bool(OPT_NO_NEG))
! 882: {
! 883: if (!searched_soa)
! 884: {
! 885: searched_soa = 1;
! 886: ttl = find_soa(header, qlen, NULL);
! 887: }
! 888: if (ttl)
! 889: cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
! 890: }
! 891: }
! 892: else
! 893: {
! 894: /* everything other than PTR */
! 895: struct crec *newc;
! 896: int addrlen;
! 897:
! 898: if (qtype == T_A)
! 899: {
! 900: addrlen = INADDRSZ;
! 901: flags |= F_IPV4;
! 902: }
! 903: #ifdef HAVE_IPV6
! 904: else if (qtype == T_AAAA)
! 905: {
! 906: addrlen = IN6ADDRSZ;
! 907: flags |= F_IPV6;
! 908: }
! 909: #endif
! 910: else
! 911: continue;
! 912:
! 913: if (!(flags & F_NXDOMAIN))
! 914: {
! 915: cname_loop1:
! 916: if (!(p1 = skip_questions(header, qlen)))
! 917: return 0;
! 918:
! 919: for (j = ntohs(header->ancount); j != 0; j--)
! 920: {
! 921: if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
! 922: return 0; /* bad packet */
! 923:
! 924: GETSHORT(aqtype, p1);
! 925: GETSHORT(aqclass, p1);
! 926: GETLONG(attl, p1);
! 927: if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
! 928: {
! 929: (p1) -= 4;
! 930: PUTLONG(daemon->max_ttl, p1);
! 931: }
! 932: GETSHORT(ardlen, p1);
! 933: endrr = p1+ardlen;
! 934:
! 935: if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
! 936: {
! 937: if (aqtype == T_CNAME)
! 938: {
! 939: if (!cname_count--)
! 940: return 0; /* looped CNAMES */
! 941: newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
! 942: if (newc)
! 943: {
! 944: newc->addr.cname.cache = NULL;
! 945: if (cpp)
! 946: {
! 947: cpp->addr.cname.cache = newc;
! 948: cpp->addr.cname.uid = newc->uid;
! 949: }
! 950: }
! 951:
! 952: cpp = newc;
! 953: if (attl < cttl)
! 954: cttl = attl;
! 955:
! 956: if (!extract_name(header, qlen, &p1, name, 1, 0))
! 957: return 0;
! 958: goto cname_loop1;
! 959: }
! 960: else
! 961: {
! 962: found = 1;
! 963:
! 964: /* copy address into aligned storage */
! 965: if (!CHECK_LEN(header, p1, qlen, addrlen))
! 966: return 0; /* bad packet */
! 967: memcpy(&addr, p1, addrlen);
! 968:
! 969: /* check for returned address in private space */
! 970: if (check_rebind &&
! 971: (flags & F_IPV4) &&
! 972: private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
! 973: return 1;
! 974:
! 975: #ifdef HAVE_IPSET
! 976: if (ipsets && (flags & (F_IPV4 | F_IPV6)))
! 977: {
! 978: ipsets_cur = ipsets;
! 979: while (*ipsets_cur)
! 980: add_to_ipset(*ipsets_cur++, &addr, flags, 0);
! 981: }
! 982: #endif
! 983:
! 984: newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
! 985: if (newc && cpp)
! 986: {
! 987: cpp->addr.cname.cache = newc;
! 988: cpp->addr.cname.uid = newc->uid;
! 989: }
! 990: cpp = NULL;
! 991: }
! 992: }
! 993:
! 994: p1 = endrr;
! 995: if (!CHECK_LEN(header, p1, qlen, 0))
! 996: return 0; /* bad packet */
! 997: }
! 998: }
! 999:
! 1000: if (!found && !option_bool(OPT_NO_NEG))
! 1001: {
! 1002: if (!searched_soa)
! 1003: {
! 1004: searched_soa = 1;
! 1005: ttl = find_soa(header, qlen, NULL);
! 1006: }
! 1007: /* If there's no SOA to get the TTL from, but there is a CNAME
! 1008: pointing at this, inherit its TTL */
! 1009: if (ttl || cpp)
! 1010: {
! 1011: newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
! 1012: if (newc && cpp)
! 1013: {
! 1014: cpp->addr.cname.cache = newc;
! 1015: cpp->addr.cname.uid = newc->uid;
! 1016: }
! 1017: }
! 1018: }
! 1019: }
! 1020: }
! 1021:
! 1022: /* Don't put stuff from a truncated packet into the cache.
! 1023: Don't cache replies where DNSSEC validation was turned off, either
! 1024: the upstream server told us so, or the original query specified it.
! 1025: Don't cache replies from non-recursive nameservers, since we may get a
! 1026: reply containing a CNAME but not its target, even though the target
! 1027: does exist. */
! 1028: if (!(header->hb3 & HB3_TC) &&
! 1029: !(header->hb4 & HB4_CD) &&
! 1030: (header->hb4 & HB4_RA) &&
! 1031: !checking_disabled)
! 1032: cache_end_insert();
! 1033:
! 1034: return 0;
! 1035: }
! 1036:
! 1037: /* If the packet holds exactly one query
! 1038: return F_IPV4 or F_IPV6 and leave the name from the query in name */
! 1039:
! 1040: unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
! 1041: {
! 1042: unsigned char *p = (unsigned char *)(header+1);
! 1043: int qtype, qclass;
! 1044:
! 1045: if (typep)
! 1046: *typep = 0;
! 1047:
! 1048: if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
! 1049: return 0; /* must be exactly one query. */
! 1050:
! 1051: if (!extract_name(header, qlen, &p, name, 1, 4))
! 1052: return 0; /* bad packet */
! 1053:
! 1054: GETSHORT(qtype, p);
! 1055: GETSHORT(qclass, p);
! 1056:
! 1057: if (typep)
! 1058: *typep = qtype;
! 1059:
! 1060: if (qclass == C_IN)
! 1061: {
! 1062: if (qtype == T_A)
! 1063: return F_IPV4;
! 1064: if (qtype == T_AAAA)
! 1065: return F_IPV6;
! 1066: if (qtype == T_ANY)
! 1067: return F_IPV4 | F_IPV6;
! 1068: }
! 1069:
! 1070: return F_QUERY;
! 1071: }
! 1072:
! 1073:
! 1074: size_t setup_reply(struct dns_header *header, size_t qlen,
! 1075: struct all_addr *addrp, unsigned int flags, unsigned long ttl)
! 1076: {
! 1077: unsigned char *p = skip_questions(header, qlen);
! 1078:
! 1079: /* clear authoritative and truncated flags, set QR flag */
! 1080: header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
! 1081: /* set RA flag */
! 1082: header->hb4 |= HB4_RA;
! 1083:
! 1084: header->nscount = htons(0);
! 1085: header->arcount = htons(0);
! 1086: header->ancount = htons(0); /* no answers unless changed below */
! 1087: if (flags == F_NEG)
! 1088: SET_RCODE(header, SERVFAIL); /* couldn't get memory */
! 1089: else if (flags == F_NOERR)
! 1090: SET_RCODE(header, NOERROR); /* empty domain */
! 1091: else if (flags == F_NXDOMAIN)
! 1092: SET_RCODE(header, NXDOMAIN);
! 1093: else if (p && flags == F_IPV4)
! 1094: { /* we know the address */
! 1095: SET_RCODE(header, NOERROR);
! 1096: header->ancount = htons(1);
! 1097: header->hb3 |= HB3_AA;
! 1098: add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
! 1099: }
! 1100: #ifdef HAVE_IPV6
! 1101: else if (p && flags == F_IPV6)
! 1102: {
! 1103: SET_RCODE(header, NOERROR);
! 1104: header->ancount = htons(1);
! 1105: header->hb3 |= HB3_AA;
! 1106: add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
! 1107: }
! 1108: #endif
! 1109: else /* nowhere to forward to */
! 1110: SET_RCODE(header, REFUSED);
! 1111:
! 1112: return p - (unsigned char *)header;
! 1113: }
! 1114:
! 1115: /* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
! 1116: int check_for_local_domain(char *name, time_t now)
! 1117: {
! 1118: struct crec *crecp;
! 1119: struct mx_srv_record *mx;
! 1120: struct txt_record *txt;
! 1121: struct interface_name *intr;
! 1122: struct ptr_record *ptr;
! 1123: struct naptr *naptr;
! 1124:
! 1125: if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
! 1126: (crecp->flags & (F_HOSTS | F_DHCP)))
! 1127: return 1;
! 1128:
! 1129: for (naptr = daemon->naptr; naptr; naptr = naptr->next)
! 1130: if (hostname_isequal(name, naptr->name))
! 1131: return 1;
! 1132:
! 1133: for (mx = daemon->mxnames; mx; mx = mx->next)
! 1134: if (hostname_isequal(name, mx->name))
! 1135: return 1;
! 1136:
! 1137: for (txt = daemon->txt; txt; txt = txt->next)
! 1138: if (hostname_isequal(name, txt->name))
! 1139: return 1;
! 1140:
! 1141: for (intr = daemon->int_names; intr; intr = intr->next)
! 1142: if (hostname_isequal(name, intr->name))
! 1143: return 1;
! 1144:
! 1145: for (ptr = daemon->ptr; ptr; ptr = ptr->next)
! 1146: if (hostname_isequal(name, ptr->name))
! 1147: return 1;
! 1148:
! 1149: return 0;
! 1150: }
! 1151:
! 1152: /* Is the packet a reply with the answer address equal to addr?
! 1153: If so mung is into an NXDOMAIN reply and also put that information
! 1154: in the cache. */
! 1155: int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
! 1156: struct bogus_addr *baddr, time_t now)
! 1157: {
! 1158: unsigned char *p;
! 1159: int i, qtype, qclass, rdlen;
! 1160: unsigned long ttl;
! 1161: struct bogus_addr *baddrp;
! 1162:
! 1163: /* skip over questions */
! 1164: if (!(p = skip_questions(header, qlen)))
! 1165: return 0; /* bad packet */
! 1166:
! 1167: for (i = ntohs(header->ancount); i != 0; i--)
! 1168: {
! 1169: if (!extract_name(header, qlen, &p, name, 1, 10))
! 1170: return 0; /* bad packet */
! 1171:
! 1172: GETSHORT(qtype, p);
! 1173: GETSHORT(qclass, p);
! 1174: GETLONG(ttl, p);
! 1175: GETSHORT(rdlen, p);
! 1176:
! 1177: if (qclass == C_IN && qtype == T_A)
! 1178: {
! 1179: if (!CHECK_LEN(header, p, qlen, INADDRSZ))
! 1180: return 0;
! 1181:
! 1182: for (baddrp = baddr; baddrp; baddrp = baddrp->next)
! 1183: if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
! 1184: {
! 1185: /* Found a bogus address. Insert that info here, since there no SOA record
! 1186: to get the ttl from in the normal processing */
! 1187: cache_start_insert();
! 1188: cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
! 1189: cache_end_insert();
! 1190:
! 1191: return 1;
! 1192: }
! 1193: }
! 1194:
! 1195: if (!ADD_RDLEN(header, p, qlen, rdlen))
! 1196: return 0;
! 1197: }
! 1198:
! 1199: return 0;
! 1200: }
! 1201:
! 1202: int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
! 1203: unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
! 1204: {
! 1205: va_list ap;
! 1206: unsigned char *sav, *p = *pp;
! 1207: int j;
! 1208: unsigned short usval;
! 1209: long lval;
! 1210: char *sval;
! 1211:
! 1212: if (truncp && *truncp)
! 1213: return 0;
! 1214:
! 1215: va_start(ap, format); /* make ap point to 1st unamed argument */
! 1216:
! 1217: if (nameoffset > 0)
! 1218: {
! 1219: PUTSHORT(nameoffset | 0xc000, p);
! 1220: }
! 1221: else
! 1222: {
! 1223: char *name = va_arg(ap, char *);
! 1224: if (name)
! 1225: p = do_rfc1035_name(p, name);
! 1226: if (nameoffset < 0)
! 1227: {
! 1228: PUTSHORT(-nameoffset | 0xc000, p);
! 1229: }
! 1230: else
! 1231: *p++ = 0;
! 1232: }
! 1233:
! 1234: PUTSHORT(type, p);
! 1235: PUTSHORT(class, p);
! 1236: PUTLONG(ttl, p); /* TTL */
! 1237:
! 1238: sav = p; /* Save pointer to RDLength field */
! 1239: PUTSHORT(0, p); /* Placeholder RDLength */
! 1240:
! 1241: for (; *format; format++)
! 1242: switch (*format)
! 1243: {
! 1244: #ifdef HAVE_IPV6
! 1245: case '6':
! 1246: sval = va_arg(ap, char *);
! 1247: memcpy(p, sval, IN6ADDRSZ);
! 1248: p += IN6ADDRSZ;
! 1249: break;
! 1250: #endif
! 1251:
! 1252: case '4':
! 1253: sval = va_arg(ap, char *);
! 1254: memcpy(p, sval, INADDRSZ);
! 1255: p += INADDRSZ;
! 1256: break;
! 1257:
! 1258: case 's':
! 1259: usval = va_arg(ap, int);
! 1260: PUTSHORT(usval, p);
! 1261: break;
! 1262:
! 1263: case 'l':
! 1264: lval = va_arg(ap, long);
! 1265: PUTLONG(lval, p);
! 1266: break;
! 1267:
! 1268: case 'd':
! 1269: /* get domain-name answer arg and store it in RDATA field */
! 1270: if (offset)
! 1271: *offset = p - (unsigned char *)header;
! 1272: p = do_rfc1035_name(p, va_arg(ap, char *));
! 1273: *p++ = 0;
! 1274: break;
! 1275:
! 1276: case 't':
! 1277: usval = va_arg(ap, int);
! 1278: sval = va_arg(ap, char *);
! 1279: if (usval != 0)
! 1280: memcpy(p, sval, usval);
! 1281: p += usval;
! 1282: break;
! 1283:
! 1284: case 'z':
! 1285: sval = va_arg(ap, char *);
! 1286: usval = sval ? strlen(sval) : 0;
! 1287: if (usval > 255)
! 1288: usval = 255;
! 1289: *p++ = (unsigned char)usval;
! 1290: memcpy(p, sval, usval);
! 1291: p += usval;
! 1292: break;
! 1293: }
! 1294:
! 1295: va_end(ap); /* clean up variable argument pointer */
! 1296:
! 1297: j = p - sav - 2;
! 1298: PUTSHORT(j, sav); /* Now, store real RDLength */
! 1299:
! 1300: /* check for overflow of buffer */
! 1301: if (limit && ((unsigned char *)limit - p) < 0)
! 1302: {
! 1303: if (truncp)
! 1304: *truncp = 1;
! 1305: return 0;
! 1306: }
! 1307:
! 1308: *pp = p;
! 1309: return 1;
! 1310: }
! 1311:
! 1312: static unsigned long crec_ttl(struct crec *crecp, time_t now)
! 1313: {
! 1314: /* Return 0 ttl for DHCP entries, which might change
! 1315: before the lease expires. */
! 1316:
! 1317: if (crecp->flags & (F_IMMORTAL | F_DHCP))
! 1318: return daemon->local_ttl;
! 1319:
! 1320: /* Return the Max TTL value if it is lower then the actual TTL */
! 1321: if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
! 1322: return crecp->ttd - now;
! 1323: else
! 1324: return daemon->max_ttl;
! 1325: }
! 1326:
! 1327:
! 1328: /* return zero if we can't answer from cache, or packet size if we can */
! 1329: size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
! 1330: struct in_addr local_addr, struct in_addr local_netmask, time_t now)
! 1331: {
! 1332: char *name = daemon->namebuff;
! 1333: unsigned char *p, *ansp, *pheader;
! 1334: int qtype, qclass;
! 1335: struct all_addr addr;
! 1336: int nameoffset;
! 1337: unsigned short flag;
! 1338: int q, ans, anscount = 0, addncount = 0;
! 1339: int dryrun = 0, sec_reqd = 0;
! 1340: int is_sign;
! 1341: struct crec *crecp;
! 1342: int nxdomain = 0, auth = 1, trunc = 0;
! 1343: struct mx_srv_record *rec;
! 1344:
! 1345: /* If there is an RFC2671 pseudoheader then it will be overwritten by
! 1346: partial replies, so we have to do a dry run to see if we can answer
! 1347: the query. We check to see if the do bit is set, if so we always
! 1348: forward rather than answering from the cache, which doesn't include
! 1349: security information. */
! 1350:
! 1351: if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
! 1352: {
! 1353: unsigned short udpsz, flags;
! 1354: unsigned char *psave = pheader;
! 1355:
! 1356: GETSHORT(udpsz, pheader);
! 1357: pheader += 2; /* ext_rcode */
! 1358: GETSHORT(flags, pheader);
! 1359:
! 1360: sec_reqd = flags & 0x8000; /* do bit */
! 1361:
! 1362: /* If our client is advertising a larger UDP packet size
! 1363: than we allow, trim it so that we don't get an overlarge
! 1364: response from upstream */
! 1365:
! 1366: if (!is_sign && (udpsz > daemon->edns_pktsz))
! 1367: PUTSHORT(daemon->edns_pktsz, psave);
! 1368:
! 1369: dryrun = 1;
! 1370: }
! 1371:
! 1372: if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
! 1373: return 0;
! 1374:
! 1375: for (rec = daemon->mxnames; rec; rec = rec->next)
! 1376: rec->offset = 0;
! 1377:
! 1378: rerun:
! 1379: /* determine end of question section (we put answers there) */
! 1380: if (!(ansp = skip_questions(header, qlen)))
! 1381: return 0; /* bad packet */
! 1382:
! 1383: /* now process each question, answers go in RRs after the question */
! 1384: p = (unsigned char *)(header+1);
! 1385:
! 1386: for (q = ntohs(header->qdcount); q != 0; q--)
! 1387: {
! 1388: /* save pointer to name for copying into answers */
! 1389: nameoffset = p - (unsigned char *)header;
! 1390:
! 1391: /* now extract name as .-concatenated string into name */
! 1392: if (!extract_name(header, qlen, &p, name, 1, 4))
! 1393: return 0; /* bad packet */
! 1394:
! 1395: GETSHORT(qtype, p);
! 1396: GETSHORT(qclass, p);
! 1397:
! 1398: ans = 0; /* have we answered this question */
! 1399:
! 1400: if (qtype == T_TXT || qtype == T_ANY)
! 1401: {
! 1402: struct txt_record *t;
! 1403: for(t = daemon->txt; t ; t = t->next)
! 1404: {
! 1405: if (t->class == qclass && hostname_isequal(name, t->name))
! 1406: {
! 1407: ans = 1;
! 1408: if (!dryrun)
! 1409: {
! 1410: log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
! 1411: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1412: daemon->local_ttl, NULL,
! 1413: T_TXT, t->class, "t", t->len, t->txt))
! 1414: anscount++;
! 1415:
! 1416: }
! 1417: }
! 1418: }
! 1419: }
! 1420:
! 1421: if (qclass == C_IN)
! 1422: {
! 1423: struct txt_record *t;
! 1424:
! 1425: for (t = daemon->rr; t; t = t->next)
! 1426: if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
! 1427: {
! 1428: ans = 1;
! 1429: if (!dryrun)
! 1430: {
! 1431: log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
! 1432: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1433: daemon->local_ttl, NULL,
! 1434: t->class, C_IN, "t", t->len, t->txt))
! 1435: anscount ++;
! 1436: }
! 1437: }
! 1438:
! 1439: if (qtype == T_PTR || qtype == T_ANY)
! 1440: {
! 1441: /* see if it's w.z.y.z.in-addr.arpa format */
! 1442: int is_arpa = in_arpa_name_2_addr(name, &addr);
! 1443: struct ptr_record *ptr;
! 1444: struct interface_name* intr = NULL;
! 1445:
! 1446: for (ptr = daemon->ptr; ptr; ptr = ptr->next)
! 1447: if (hostname_isequal(name, ptr->name))
! 1448: break;
! 1449:
! 1450: if (is_arpa == F_IPV4)
! 1451: for (intr = daemon->int_names; intr; intr = intr->next)
! 1452: {
! 1453: if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
! 1454: break;
! 1455: else
! 1456: while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
! 1457: intr = intr->next;
! 1458: }
! 1459:
! 1460: if (intr)
! 1461: {
! 1462: ans = 1;
! 1463: if (!dryrun)
! 1464: {
! 1465: log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
! 1466: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1467: daemon->local_ttl, NULL,
! 1468: T_PTR, C_IN, "d", intr->name))
! 1469: anscount++;
! 1470: }
! 1471: }
! 1472: else if (ptr)
! 1473: {
! 1474: ans = 1;
! 1475: if (!dryrun)
! 1476: {
! 1477: log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
! 1478: for (ptr = daemon->ptr; ptr; ptr = ptr->next)
! 1479: if (hostname_isequal(name, ptr->name) &&
! 1480: add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1481: daemon->local_ttl, NULL,
! 1482: T_PTR, C_IN, "d", ptr->ptr))
! 1483: anscount++;
! 1484:
! 1485: }
! 1486: }
! 1487: else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
! 1488: do
! 1489: {
! 1490: /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
! 1491: if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
! 1492: continue;
! 1493:
! 1494: if (crecp->flags & F_NEG)
! 1495: {
! 1496: ans = 1;
! 1497: auth = 0;
! 1498: if (crecp->flags & F_NXDOMAIN)
! 1499: nxdomain = 1;
! 1500: if (!dryrun)
! 1501: log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
! 1502: }
! 1503: else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
! 1504: {
! 1505: ans = 1;
! 1506: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 1507: auth = 0;
! 1508: if (!dryrun)
! 1509: {
! 1510: log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
! 1511: record_source(crecp->uid));
! 1512:
! 1513: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1514: crec_ttl(crecp, now), NULL,
! 1515: T_PTR, C_IN, "d", cache_get_name(crecp)))
! 1516: anscount++;
! 1517: }
! 1518: }
! 1519: } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
! 1520: else if (is_arpa == F_IPV4 &&
! 1521: option_bool(OPT_BOGUSPRIV) &&
! 1522: private_net(addr.addr.addr4, 1))
! 1523: {
! 1524: /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
! 1525: ans = 1;
! 1526: nxdomain = 1;
! 1527: if (!dryrun)
! 1528: log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
! 1529: name, &addr, NULL);
! 1530: }
! 1531: }
! 1532:
! 1533: for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
! 1534: {
! 1535: unsigned short type = T_A;
! 1536:
! 1537: if (flag == F_IPV6)
! 1538: #ifdef HAVE_IPV6
! 1539: type = T_AAAA;
! 1540: #else
! 1541: break;
! 1542: #endif
! 1543:
! 1544: if (qtype != type && qtype != T_ANY)
! 1545: continue;
! 1546:
! 1547: /* Check for "A for A" queries; be rather conservative
! 1548: about what looks like dotted-quad. */
! 1549: if (qtype == T_A)
! 1550: {
! 1551: char *cp;
! 1552: unsigned int i, a;
! 1553: int x;
! 1554:
! 1555: for (cp = name, i = 0, a = 0; *cp; i++)
! 1556: {
! 1557: if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
! 1558: {
! 1559: i = 5;
! 1560: break;
! 1561: }
! 1562:
! 1563: a = (a << 8) + x;
! 1564:
! 1565: if (*cp == '.')
! 1566: cp++;
! 1567: }
! 1568:
! 1569: if (i == 4)
! 1570: {
! 1571: ans = 1;
! 1572: if (!dryrun)
! 1573: {
! 1574: addr.addr.addr4.s_addr = htonl(a);
! 1575: log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
! 1576: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1577: daemon->local_ttl, NULL, type, C_IN, "4", &addr))
! 1578: anscount++;
! 1579: }
! 1580: continue;
! 1581: }
! 1582: }
! 1583:
! 1584: /* interface name stuff */
! 1585: if (qtype == T_A)
! 1586: {
! 1587: struct interface_name *intr;
! 1588:
! 1589: for (intr = daemon->int_names; intr; intr = intr->next)
! 1590: if (hostname_isequal(name, intr->name))
! 1591: break;
! 1592:
! 1593: if (intr)
! 1594: {
! 1595: ans = 1;
! 1596: if (!dryrun)
! 1597: {
! 1598: if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
! 1599: log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
! 1600: else
! 1601: {
! 1602: log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
! 1603: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1604: daemon->local_ttl, NULL, type, C_IN, "4", &addr))
! 1605: anscount++;
! 1606: }
! 1607: }
! 1608: continue;
! 1609: }
! 1610: }
! 1611:
! 1612: cname_restart:
! 1613: if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
! 1614: {
! 1615: int localise = 0;
! 1616:
! 1617: /* See if a putative address is on the network from which we recieved
! 1618: the query, is so we'll filter other answers. */
! 1619: if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
! 1620: {
! 1621: struct crec *save = crecp;
! 1622: do {
! 1623: if ((crecp->flags & F_HOSTS) &&
! 1624: is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
! 1625: {
! 1626: localise = 1;
! 1627: break;
! 1628: }
! 1629: } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
! 1630: crecp = save;
! 1631: }
! 1632:
! 1633: do
! 1634: {
! 1635: /* don't answer wildcard queries with data not from /etc/hosts
! 1636: or DHCP leases */
! 1637: if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
! 1638: break;
! 1639:
! 1640: if (crecp->flags & F_CNAME)
! 1641: {
! 1642: if (!dryrun)
! 1643: {
! 1644: log_query(crecp->flags, name, NULL, record_source(crecp->uid));
! 1645: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1646: crec_ttl(crecp, now), &nameoffset,
! 1647: T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
! 1648: anscount++;
! 1649: }
! 1650:
! 1651: strcpy(name, cache_get_name(crecp->addr.cname.cache));
! 1652: goto cname_restart;
! 1653: }
! 1654:
! 1655: if (crecp->flags & F_NEG)
! 1656: {
! 1657: ans = 1;
! 1658: auth = 0;
! 1659: if (crecp->flags & F_NXDOMAIN)
! 1660: nxdomain = 1;
! 1661: if (!dryrun)
! 1662: log_query(crecp->flags, name, NULL, NULL);
! 1663: }
! 1664: else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
! 1665: {
! 1666: /* If we are returning local answers depending on network,
! 1667: filter here. */
! 1668: if (localise &&
! 1669: (crecp->flags & F_HOSTS) &&
! 1670: !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
! 1671: continue;
! 1672:
! 1673: if (!(crecp->flags & (F_HOSTS | F_DHCP)))
! 1674: auth = 0;
! 1675:
! 1676: ans = 1;
! 1677: if (!dryrun)
! 1678: {
! 1679: log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
! 1680: record_source(crecp->uid));
! 1681:
! 1682: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1683: crec_ttl(crecp, now), NULL, type, C_IN,
! 1684: type == T_A ? "4" : "6", &crecp->addr))
! 1685: anscount++;
! 1686: }
! 1687: }
! 1688: } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
! 1689: }
! 1690: }
! 1691:
! 1692: if (qtype == T_CNAME || qtype == T_ANY)
! 1693: {
! 1694: if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
! 1695: (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP))))
! 1696: {
! 1697: ans = 1;
! 1698: if (!dryrun)
! 1699: {
! 1700: log_query(crecp->flags, name, NULL, record_source(crecp->uid));
! 1701: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
! 1702: crec_ttl(crecp, now), &nameoffset,
! 1703: T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
! 1704: anscount++;
! 1705: }
! 1706: }
! 1707: }
! 1708:
! 1709: if (qtype == T_MX || qtype == T_ANY)
! 1710: {
! 1711: int found = 0;
! 1712: for (rec = daemon->mxnames; rec; rec = rec->next)
! 1713: if (!rec->issrv && hostname_isequal(name, rec->name))
! 1714: {
! 1715: ans = found = 1;
! 1716: if (!dryrun)
! 1717: {
! 1718: int offset;
! 1719: log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
! 1720: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
! 1721: &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
! 1722: {
! 1723: anscount++;
! 1724: if (rec->target)
! 1725: rec->offset = offset;
! 1726: }
! 1727: }
! 1728: }
! 1729:
! 1730: if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
! 1731: cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
! 1732: {
! 1733: ans = 1;
! 1734: if (!dryrun)
! 1735: {
! 1736: log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
! 1737: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
! 1738: T_MX, C_IN, "sd", 1,
! 1739: option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
! 1740: anscount++;
! 1741: }
! 1742: }
! 1743: }
! 1744:
! 1745: if (qtype == T_SRV || qtype == T_ANY)
! 1746: {
! 1747: int found = 0;
! 1748: struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
! 1749:
! 1750: for (rec = daemon->mxnames; rec; rec = rec->next)
! 1751: if (rec->issrv && hostname_isequal(name, rec->name))
! 1752: {
! 1753: found = ans = 1;
! 1754: if (!dryrun)
! 1755: {
! 1756: int offset;
! 1757: log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
! 1758: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
! 1759: &offset, T_SRV, C_IN, "sssd",
! 1760: rec->priority, rec->weight, rec->srvport, rec->target))
! 1761: {
! 1762: anscount++;
! 1763: if (rec->target)
! 1764: rec->offset = offset;
! 1765: }
! 1766: }
! 1767:
! 1768: /* unlink first SRV record found */
! 1769: if (!move)
! 1770: {
! 1771: move = rec;
! 1772: *up = rec->next;
! 1773: }
! 1774: else
! 1775: up = &rec->next;
! 1776: }
! 1777: else
! 1778: up = &rec->next;
! 1779:
! 1780: /* put first SRV record back at the end. */
! 1781: if (move)
! 1782: {
! 1783: *up = move;
! 1784: move->next = NULL;
! 1785: }
! 1786:
! 1787: if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
! 1788: {
! 1789: ans = 1;
! 1790: if (!dryrun)
! 1791: log_query(F_CONFIG | F_NEG, name, NULL, NULL);
! 1792: }
! 1793: }
! 1794:
! 1795: if (qtype == T_NAPTR || qtype == T_ANY)
! 1796: {
! 1797: struct naptr *na;
! 1798: for (na = daemon->naptr; na; na = na->next)
! 1799: if (hostname_isequal(name, na->name))
! 1800: {
! 1801: ans = 1;
! 1802: if (!dryrun)
! 1803: {
! 1804: log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
! 1805: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
! 1806: NULL, T_NAPTR, C_IN, "sszzzd",
! 1807: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
! 1808: anscount++;
! 1809: }
! 1810: }
! 1811: }
! 1812:
! 1813: if (qtype == T_MAILB)
! 1814: ans = 1, nxdomain = 1;
! 1815:
! 1816: if (qtype == T_SOA && option_bool(OPT_FILTER))
! 1817: {
! 1818: ans = 1;
! 1819: if (!dryrun)
! 1820: log_query(F_CONFIG | F_NEG, name, &addr, NULL);
! 1821: }
! 1822: }
! 1823:
! 1824: if (!ans)
! 1825: return 0; /* failed to answer a question */
! 1826: }
! 1827:
! 1828: if (dryrun)
! 1829: {
! 1830: dryrun = 0;
! 1831: goto rerun;
! 1832: }
! 1833:
! 1834: /* create an additional data section, for stuff in SRV and MX record replies. */
! 1835: for (rec = daemon->mxnames; rec; rec = rec->next)
! 1836: if (rec->offset != 0)
! 1837: {
! 1838: /* squash dupes */
! 1839: struct mx_srv_record *tmp;
! 1840: for (tmp = rec->next; tmp; tmp = tmp->next)
! 1841: if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
! 1842: tmp->offset = 0;
! 1843:
! 1844: crecp = NULL;
! 1845: while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
! 1846: {
! 1847: #ifdef HAVE_IPV6
! 1848: int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
! 1849: #else
! 1850: int type = T_A;
! 1851: #endif
! 1852: if (crecp->flags & F_NEG)
! 1853: continue;
! 1854:
! 1855: if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
! 1856: crec_ttl(crecp, now), NULL, type, C_IN,
! 1857: crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
! 1858: addncount++;
! 1859: }
! 1860: }
! 1861:
! 1862: /* done all questions, set up header and return length of result */
! 1863: /* clear authoritative and truncated flags, set QR flag */
! 1864: header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
! 1865: /* set RA flag */
! 1866: header->hb4 |= HB4_RA;
! 1867:
! 1868: /* authoritive - only hosts and DHCP derived names. */
! 1869: if (auth)
! 1870: header->hb3 |= HB3_AA;
! 1871:
! 1872: /* truncation */
! 1873: if (trunc)
! 1874: header->hb3 |= HB3_TC;
! 1875:
! 1876: if (anscount == 0 && nxdomain)
! 1877: SET_RCODE(header, NXDOMAIN);
! 1878: else
! 1879: SET_RCODE(header, NOERROR); /* no error */
! 1880: header->ancount = htons(anscount);
! 1881: header->nscount = htons(0);
! 1882: header->arcount = htons(addncount);
! 1883: return ansp - (unsigned char *)header;
! 1884: }
! 1885:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>