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

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

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