File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / auth.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 2 weeks ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #ifdef HAVE_AUTH
   20: 
   21: static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
   22: {
   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: }
   43: 
   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: }
   51: 
   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);
   58: }
   59: 
   60: static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
   61: {
   62:   if (find_exclude(zone, flag, addr_u))
   63:     return 0;
   64: 
   65:   /* No subnets specified, no filter */
   66:   if (!zone->subnet)
   67:     return 1;
   68:   
   69:   return find_subnet(zone, flag, addr_u) != NULL;
   70: }
   71: 
   72: int in_zone(struct auth_zone *zone, char *name, char **cut)
   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: 
   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) 
  101: {
  102:   char *name = daemon->namebuff;
  103:   unsigned char *p, *ansp;
  104:   int qtype, qclass, rc;
  105:   int nameoffset, axfroffset = 0;
  106:   int q, anscount = 0, authcount = 0;
  107:   struct crec *crecp;
  108:   int  auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
  109:   struct auth_zone *zone = NULL;
  110:   struct addrlist *subnet = NULL;
  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;
  116:   union all_addr addr;
  117:   struct cname *a, *candidate;
  118:   unsigned int wclen;
  119:   
  120:   if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
  121:     return 0;
  122: 
  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:     {
  132:       unsigned int flag = 0;
  133:       int found = 0;
  134:       int cname_wildcard = 0;
  135:   
  136:       /* save pointer to name for copying into answers */
  137:       nameoffset = p - (unsigned char *)header;
  138: 
  139:       /* now extract name as .-concatenated string into name */
  140:       if (!extract_name(header, qlen, &p, name, 1, 4))
  141: 	return 0; /* bad packet */
  142:  
  143:       GETSHORT(qtype, p); 
  144:       GETSHORT(qclass, p);
  145:       
  146:       if (qclass != C_IN)
  147: 	{
  148: 	  auth = 0;
  149: 	  out_of_zone = 1;
  150: 	  continue;
  151: 	}
  152: 
  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)
  162: 	    {
  163: 	      out_of_zone = 1;
  164: 	      auth = 0;
  165: 	      continue;
  166: 	    }
  167: 	  else if (qtype == T_SOA)
  168: 	    soa = 1, found = 1;
  169: 	  else if (qtype == T_NS)
  170: 	    ns = 1, found = 1;
  171: 	}
  172: 
  173:       if (qtype == T_PTR && flag)
  174: 	{
  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)
  183: 		  if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
  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)
  198: 		  if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
  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: 	    {
  210: 	      if (local_query || in_zone(zone, intr->name, NULL))
  211: 		{	
  212: 		  found = 1;
  213: 		  log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
  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++;
  218: 		}
  219: 	    }
  220: 	  
  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 */
  232: 		  if (zone)
  233: 		    {
  234: 		      strcat(name, ".");
  235: 		      strcat(name, zone->domain);
  236: 		    }
  237: 		  log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
  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: 		}
  244: 	      else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
  245: 		{
  246: 		  log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
  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: 
  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: 
  269: 	  if (found)
  270: 	    nxdomain = 0;
  271: 	  else
  272: 	    log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
  273: 
  274: 	  continue;
  275: 	}
  276:       
  277:     cname_restart:
  278:       if (found)
  279: 	/* NS and SOA .arpa requests have set found above. */
  280: 	cut = NULL;
  281:       else
  282: 	{
  283: 	  for (zone = daemon->auth_zones; zone; zone = zone->next)
  284: 	    if (in_zone(zone, name, &cut))
  285: 	      break;
  286: 	  
  287: 	  if (!zone)
  288: 	    {
  289: 	      out_of_zone = 1;
  290: 	      auth = 0;
  291: 	      continue;
  292: 	    }
  293: 	}
  294: 
  295:       for (rec = daemon->mxnames; rec; rec = rec->next)
  296: 	if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
  297: 	  {
  298: 	    nxdomain = 0;
  299: 	         
  300: 	    if (rc == 2 && qtype == T_MX)
  301: 	      {
  302: 		found = 1;
  303: 		log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
  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)
  311: 	if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
  312: 	  {
  313: 	    nxdomain = 0;
  314: 	    
  315: 	    if (rc == 2 && qtype == T_SRV)
  316: 	      {
  317: 		found = 1;
  318: 		log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
  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)
  346: 	if ((rc = hostname_issubdomain(name, txt->name)))
  347: 	  {
  348: 	    nxdomain = 0;
  349: 	    if (rc == 2 && txt->class == qtype)
  350: 	      {
  351: 		found = 1;
  352: 		log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
  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)
  360: 	if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
  361: 	  {
  362: 	    nxdomain = 0;
  363: 	    if (rc == 2 && qtype == T_TXT)
  364: 	      {
  365: 		found = 1;
  366: 		log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
  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)
  374: 	 if ((rc = hostname_issubdomain(name, na->name)))
  375: 	   {
  376: 	     nxdomain = 0;
  377: 	     if (rc == 2 && qtype == T_NAPTR)
  378: 	       {
  379: 		 found = 1;
  380: 		 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
  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: 	   }
  387:     
  388:        if (qtype == T_A)
  389: 	 flag = F_IPV4;
  390:        
  391:        if (qtype == T_AAAA)
  392: 	 flag = F_IPV6;
  393:        
  394:        for (intr = daemon->int_names; intr; intr = intr->next)
  395: 	 if ((rc = hostname_issubdomain(name, intr->name)))
  396: 	   {
  397: 	     struct addrlist *addrlist;
  398: 	     
  399: 	     nxdomain = 0;
  400: 	     
  401: 	     if (rc == 2 && flag)
  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: 		   {
  406: 		     if (addrlist->flags & ADDRLIST_REVONLY)
  407: 		       continue;
  408: 
  409: 		     found = 1;
  410: 		     log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
  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: 	     }
  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: 	 }
  427:        
  428:       if (!cut)
  429: 	{
  430: 	  nxdomain = 0;
  431: 	  
  432: 	  if (qtype == T_SOA)
  433: 	    {
  434: 	      auth = soa = 1; /* inhibits auth section */
  435: 	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
  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
  444: 		{
  445: 		  peer_addr->in6.sin6_port = 0; 
  446: 		  peer_addr->in6.sin6_scope_id = 0;
  447: 		}
  448: 	      
  449: 	      for (peers = daemon->auth_peers; peers; peers = peers->next)
  450: 		if (sockaddr_isequal(peer_addr, &peers->addr))
  451: 		  break;
  452: 	      
  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)) 
  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: 	       	      
  466: 	      auth = 1;
  467: 	      soa = 1; /* inhibits auth section */
  468: 	      ns = 1; /* ensure we include NS records! */
  469: 	      axfr = 1;
  470: 	      axfroffset = nameoffset;
  471: 	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
  472: 	    }
  473:       	  else if (qtype == T_NS)
  474: 	    {
  475: 	      auth = 1;
  476: 	      ns = 1; /* inhibits auth section */
  477: 	      log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
  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) && 
  492: 			(local_query || filter_zone(zone, flag, &(crecp->addr))))
  493: 		      {
  494: 			*cut = '.'; /* restore domain part */
  495: 			log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
  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;
  514: 		 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
  515: 		   {
  516: 		     log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
  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:       
  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: 	    {
  563: 	      log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
  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: 
  581: 	  log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
  582: 	}
  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: 
  600: 	  if (!(subnet->flags & ADDRLIST_IPV6))
  601: 	    {
  602: 	      in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
  603: 	      char *p = name;
  604: 	      
  605: 	      if (subnet->prefixlen >= 24)
  606: 		p += sprintf(p, "%u.", a & 0xff);
  607: 	      a = a >> 8;
  608: 	      if (subnet->prefixlen >= 16 )
  609: 		p += sprintf(p, "%u.", a & 0xff);
  610: 	      a = a >> 8;
  611: 	      sprintf(p, "%u.in-addr.arpa", a & 0xff);
  612: 	      
  613: 	    }
  614: 	  else
  615: 	    {
  616: 	      char *p = name;
  617: 	      int i;
  618: 	      
  619: 	      for (i = subnet->prefixlen-1; i >= 0; i -= 4)
  620: 		{ 
  621: 		  int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
  622: 		  p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
  623: 		}
  624: 	      sprintf(p, "ip6.arpa");
  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: 	  
  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: 		}
  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)
  753: 	    if (in_zone(zone, intr->name, &cut))
  754: 	      {
  755: 		struct addrlist *addrlist;
  756: 		
  757: 		if (cut)
  758: 		  *cut = 0;
  759: 		
  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++;
  773: 		
  774: 		/* restore config data */
  775: 		if (cut)
  776: 		  *cut = '.'; 
  777: 	      }
  778:              
  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);
  808: 		      if (!strchr(cache_name, '.') && 
  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++;
  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));
  819: 		      if (in_zone(zone, name, &cut) && 
  820: 			  (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
  821: 			{
  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++;
  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;
  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:     }
  861: 
  862:   /* data is never DNSSEC signed. */
  863:   header->hb4 &= ~HB4_AD;
  864: 
  865:   /* authoritative */
  866:   if (auth)
  867:     header->hb3 |= HB3_AA;
  868:   
  869:   /* truncation */
  870:   if (trunc)
  871:     header->hb3 |= HB3_TC;
  872:   
  873:   if ((auth || local_query) && nxdomain)
  874:     SET_RCODE(header, NXDOMAIN);
  875:   else
  876:     SET_RCODE(header, NOERROR); /* no error */
  877:   
  878:   header->ancount = htons(anscount);
  879:   header->nscount = htons(authcount);
  880:   header->arcount = htons(0);
  881: 
  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:   
  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: 
  897:   return ansp - (unsigned char *)header;
  898: }
  899:   
  900: #endif  

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