File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / coova-chilli / src / dns.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:48:25 2012 UTC (13 years, 1 month ago) by misho
Branches: coova-chilli, MAIN
CVS tags: v1_0_12, HEAD
coova-chilli

    1: /*
    2:  * DNS library functions
    3:  * Copyright (c) 2006-2008 David Bird <david@coova.com>
    4:  *
    5:  * The contents of this file may be used under the terms of the GNU
    6:  * General Public License Version 2, provided that the above copyright
    7:  * notice and this permission notice is included in all copies or
    8:  * substantial portions of the software.
    9:  *
   10:  */
   11: 
   12: #include "dns.h"
   13: #include "garden.h"
   14: #include "syserr.h"
   15: #include "dhcp.h"
   16: #include "options.h"
   17: 
   18: #define antidnstunnel options.dnsparanoia
   19: 
   20: extern struct dhcp_t *dhcp;
   21: 
   22: char *
   23: dns_fullname(char *data, size_t dlen, uint8_t *res, uint8_t *opkt, size_t olen, int lvl) {
   24:   char *d = data;
   25:   unsigned short l;
   26:   
   27:   if (lvl >= 15) 
   28:     return 0;
   29:   
   30:   while ((l = *res++) != 0) {
   31:     if ((l & 0xC0) == 0xC0) {
   32:       unsigned short offset = ((l & ~0xC0) << 8) + *res;
   33:       if (offset > olen) {
   34: 	log_dbg("bad value");
   35: 	return 0;
   36:       }
   37:       /*log_dbg("skip[%d]\n",offset);*/
   38:       dns_fullname(d, dlen, opkt + (size_t)offset, opkt, olen, lvl+1);
   39:       break;
   40:     }
   41:     
   42:     if (l >= dlen) {
   43:       log_dbg("bad value");
   44:       return 0;
   45:     }
   46:     
   47:     /*log_dbg("part[%.*s]\n",l,res);*/
   48:     
   49:     memcpy(d, res, l);
   50:     d += l; dlen -= l;
   51:     res += l;
   52:     
   53:     *d = '.';
   54:     d += 1; dlen -= 1;
   55:   }
   56:   
   57:   if (!lvl && data[strlen((char*)data)-1]=='.')
   58:     data[strlen((char*)data)-1]=0;
   59:   
   60:   return data;
   61: }
   62: 
   63: int dns_getname(uint8_t **pktp, size_t *left, char *name, size_t namesz, size_t *nameln) {
   64:   size_t namelen = *nameln;
   65:   uint8_t *p_pkt = *pktp;
   66:   size_t len = *left;
   67:   uint8_t l;
   68:   
   69:   namelen = 0;
   70:   while (len-- && (l = name[namelen++] = *p_pkt++) != 0) {
   71:     if ((l & 0xC0) == 0xC0) {
   72:       if (namelen >= namesz) {
   73: 	log_err(0, "name too long in DNS packet");
   74: 	break;
   75:       }
   76:       name[namelen++] = *p_pkt++;
   77:       len--;
   78:       break;
   79:     }
   80:   }
   81:   
   82:   *pktp = p_pkt;
   83:   *nameln = namelen;
   84:   *left = len;
   85:   
   86:   if (!len) {
   87:     log_err(0, "failed to parse DNS packet");
   88:     return -1;
   89:   }
   90:   
   91:   return 0;
   92: }
   93: 
   94: static void 
   95: add_A_to_garden(uint8_t *p) {
   96:   struct in_addr reqaddr;
   97:   pass_through pt;
   98:   memcpy(&reqaddr.s_addr, p, 4);
   99:   memset(&pt, 0, sizeof(pass_through));
  100:   pt.mask.s_addr = 0xffffffff;
  101:   pt.host = reqaddr;
  102:   if (pass_through_add(dhcp->pass_throughs,
  103: 		       MAX_PASS_THROUGHS,
  104: 		       &dhcp->num_pass_throughs,
  105: 		       &pt))
  106:     ;
  107: }
  108: 
  109: int 
  110: dns_copy_res(int q, 
  111: 	     uint8_t **pktp, size_t *left, 
  112: 	     uint8_t *opkt,  size_t olen, 
  113: 	     char *question, size_t qsize) {
  114: 
  115: #define return_error \
  116: { log_dbg("%s:%d: failed parsing DNS packet",__FILE__,__LINE__); return -1; }
  117: 
  118:   uint8_t *p_pkt = *pktp;
  119:   size_t len = *left;
  120:   
  121:   uint8_t name[PKT_IP_PLEN];
  122:   size_t namelen = 0;
  123: 
  124:   uint16_t type;
  125:   uint16_t class;
  126:   uint32_t ttl;
  127:   uint16_t rdlen;
  128: 
  129:   uint32_t ul;
  130:   uint16_t us;
  131: 
  132:   if (dns_getname(&p_pkt, &len, (char *)name, sizeof(name), &namelen)) 
  133:     return_error;
  134: 
  135:   if (antidnstunnel && namelen > 128) {
  136:     log_warn(0,"dropping dns for anti-dnstunnel (namelen: %d)",namelen);
  137:     return -1;
  138:   }
  139: 
  140:   if (len < 4) 
  141:     return_error;
  142: 
  143:   memcpy(&us, p_pkt, sizeof(us));
  144:   type = ntohs(us);
  145:   p_pkt += 2;
  146:   len -= 2;
  147:   
  148:   memcpy(&us, p_pkt, sizeof(us));
  149:   class = ntohs(us);
  150:   p_pkt += 2;
  151:   len -= 2;
  152:   
  153:   log_dbg("It was a dns record type: %d class: %d", type, class);
  154: 
  155: 
  156:   /* if dnsparanoia, checks here */
  157: 
  158:   if (antidnstunnel) {
  159:     switch (type) {
  160:     case 1:/* A */ 
  161:       log_dbg("A record");
  162:       break;
  163:     case 5:/* CNAME */ 
  164:       log_dbg("CNAME record");
  165:       break;
  166:     default:
  167:       if (options.debug) switch(type) {
  168:       case 6:  log_dbg("SOA record"); break;
  169:       case 12: log_dbg("PTR record"); break;
  170:       case 15: log_dbg("MX record");  break;
  171:       case 16: log_dbg("TXT record"); break;
  172:       default: log_dbg("Record type %d", type); break;
  173:       }
  174:       log_warn(0, "dropping dns for anti-dnstunnel (type %d: length %d)", type, rdlen);
  175:       return -1;
  176:     }
  177:   }
  178: 
  179:   if (q) {
  180:     dns_fullname(question, qsize, *pktp, opkt, olen, 0);
  181:     
  182:     log_dbg("Q: %s", question);
  183: 
  184:     *pktp = p_pkt;
  185:     *left = len;
  186: 
  187:     return 0;
  188:   } 
  189: 
  190:   if (len < 6) 
  191:     return_error;
  192:   
  193:   memcpy(&ul, p_pkt, sizeof(ul));
  194:   ttl = ntohl(ul);
  195:   p_pkt += 4;
  196:   len -= 4;
  197:   
  198:   memcpy(&us, p_pkt, sizeof(us));
  199:   rdlen = ntohs(us);
  200:   p_pkt += 2;
  201:   len -= 2;
  202:   
  203:   /*log_dbg("-> w ttl: %d rdlength: %d/%d", ttl, rdlen, len);*/
  204:   
  205:   if (len < rdlen)
  206:     return_error;
  207:   
  208:   /*
  209:    *  dns records 
  210:    */  
  211:   
  212:   switch (type) {
  213:     
  214:   case 1:/* A */
  215:     log_dbg("A record");
  216:     if (options.uamdomains) {
  217:       int id;
  218:       for (id=0; options.uamdomains[id]; id++) {
  219: 
  220: 	log_dbg("checking %s [%s]", options.uamdomains[id], question);
  221: 
  222: 	if (strlen(question) >= strlen(options.uamdomains[id]) &&
  223: 	    !strcmp(options.uamdomains[id],
  224: 		    question + (strlen(question) - strlen(options.uamdomains[id])))) {
  225: 	  size_t offset;
  226: 	  for (offset=0; offset < rdlen; offset += 4) {
  227: 	    add_A_to_garden(p_pkt+offset);
  228: 	  }
  229: 
  230: 	  break;
  231: 	}
  232:       }
  233:     }
  234:     break;
  235: 
  236:   case 5:/* CNAME */
  237:     {
  238:       char cname[256];
  239:       memset(cname,0,sizeof(cname));
  240:       dns_fullname(cname, sizeof(cname)-1, p_pkt, opkt, olen, 0);
  241:       log_dbg("CNAME record %s", cname);
  242:     }
  243:     break;
  244: 
  245:   default:
  246: 
  247:     if (options.debug) switch(type) {
  248:     case 6:  log_dbg("SOA record"); break;
  249:     case 12: log_dbg("PTR record"); break;
  250:     case 15: log_dbg("MX record");  break;
  251:     case 16: log_dbg("TXT record"); break;
  252:     default: log_dbg("Record type %d", type); break;
  253:     }
  254: 
  255:     if (antidnstunnel) {
  256:       log_warn(0, "dropping dns for anti-dnstunnel (type %d: length %d)", type, rdlen);
  257:       return -1;
  258:     }
  259: 
  260:     break;
  261:   }
  262:   
  263:   p_pkt += rdlen;
  264:   len -= rdlen;
  265:   
  266:   *pktp = p_pkt;
  267:   *left = len;
  268: 
  269:   return 0;
  270: }

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