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>