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

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

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