File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / loop.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 8 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* dnsmasq is Copyright (c) 2000-2016 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_LOOP
   20: static ssize_t loop_make_probe(u32 uid);
   21: 
   22: void loop_send_probes()
   23: {
   24:    struct server *serv;
   25:    
   26:    if (!option_bool(OPT_LOOP_DETECT))
   27:      return;
   28: 
   29:    /* Loop through all upstream servers not for particular domains, and send a query to that server which is
   30:       identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
   31:    for (serv = daemon->servers; serv; serv = serv->next)
   32:      if (!(serv->flags & 
   33: 	   (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
   34:        {
   35: 	 ssize_t len = loop_make_probe(serv->uid);
   36: 	 int fd;
   37: 	 struct randfd *rfd = NULL;
   38: 	 
   39: 	 if (serv->sfd)
   40: 	   fd = serv->sfd->fd;
   41: 	 else 
   42: 	   {
   43: 	     if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
   44: 	       continue;
   45: 	     fd = rfd->fd;
   46: 	   }
   47: 
   48: 	 while (retry_send(sendto(fd, daemon->packet, len, 0, 
   49: 				  &serv->addr.sa, sa_len(&serv->addr))));
   50: 	 
   51: 	 free_rfd(rfd);
   52:        }
   53: }
   54:   
   55: static ssize_t loop_make_probe(u32 uid)
   56: {
   57:   struct dns_header *header = (struct dns_header *)daemon->packet;
   58:   unsigned char *p = (unsigned char *)(header+1);
   59: 
   60:   /* packet buffer overwritten */
   61:   daemon->srv_save = NULL;
   62:   
   63:   header->id = rand16();
   64:   header->ancount = header->nscount = header->arcount = htons(0);
   65:   header->qdcount = htons(1);
   66:   header->hb3 = HB3_RD;
   67:   header->hb4 = 0;
   68:   SET_OPCODE(header, QUERY);
   69: 
   70:   *p++ = 8;
   71:   sprintf((char *)p, "%.8x", uid);
   72:   p += 8;
   73:   *p++ = strlen(LOOP_TEST_DOMAIN);
   74:   strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
   75:   p += strlen(LOOP_TEST_DOMAIN) + 1;
   76: 
   77:   PUTSHORT(LOOP_TEST_TYPE, p);
   78:   PUTSHORT(C_IN, p);
   79: 
   80:   return p - (unsigned char *)header;
   81: }
   82:   
   83: 
   84: int detect_loop(char *query, int type)
   85: {
   86:   int i;
   87:   u32 uid;
   88:   struct server *serv;
   89:   
   90:   if (!option_bool(OPT_LOOP_DETECT))
   91:     return 0;
   92: 
   93:   if (type != LOOP_TEST_TYPE ||
   94:       strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
   95:       strstr(query, LOOP_TEST_DOMAIN) != query + 9)
   96:     return 0;
   97: 
   98:   for (i = 0; i < 8; i++)
   99:     if (!isxdigit(query[i]))
  100:       return 0;
  101: 
  102:   uid = strtol(query, NULL, 16);
  103: 
  104:   for (serv = daemon->servers; serv; serv = serv->next)
  105:      if (!(serv->flags & 
  106: 	   (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
  107: 	 uid == serv->uid)
  108:        {
  109: 	 serv->flags |= SERV_LOOP;
  110: 	 check_servers(); /* log new state */
  111: 	 return 1;
  112:        }
  113: 
  114:   return 0;
  115: }
  116: 
  117: #endif

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