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

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

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