Annotation of embedaddon/coova-chilli/src/dns.c, revision 1.1.1.1

1.1       misho       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>