File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / auth.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:56:46 2021 UTC (3 years, 5 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_84, HEAD
dnsmasq 2.84

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

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