Annotation of embedaddon/dnsmasq/src/auth.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>