Annotation of embedaddon/coova-chilli/src/dns.c, revision 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>