Annotation of embedaddon/trafshow/domain_resolver.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     Copyright (c) 1999-2004 Rinet Corp., Novosibirsk, Russia
                      3:  *
                      4:  * Redistribution and use in source forms, with and without modification,
                      5:  * are permitted provided that this entire comment appears intact.
                      6:  *
                      7:  * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
                      8:  */
                      9: 
                     10: #ifdef HAVE_CONFIG_H
                     11: #include <config.h>
                     12: #endif
                     13: 
                     14: #include <sys/types.h>
                     15: #include <sys/param.h>
                     16: #include <sys/socket.h>
                     17: #include <netinet/in.h>
                     18: #include <arpa/inet.h>
                     19: #include <arpa/nameser.h>
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23: #include <errno.h>
                     24: #ifdef HAVE_PATHS_H
                     25: #include <paths.h>
                     26: #endif
                     27: #ifdef HAVE_RESOLV_H
                     28: #include <resolv.h>
                     29: #endif
                     30: 
                     31: #include "domain_resolver.h"
                     32: #include "session.h"
                     33: #include "util.h"
                     34: #include "trafshow.h"  /* just for dprintf() */
                     35: 
                     36: 
                     37: #ifndef        _PATH_RESCONF
                     38: #define        _PATH_RESCONF           "/etc/resolv.conf"
                     39: #endif
                     40: #ifndef        NAMESERVER_TOKEN
                     41: #define        NAMESERVER_TOKEN        "nameserver"
                     42: #endif
                     43: #ifndef        NAMESERVER_PORT
                     44: #define        NAMESERVER_PORT         53      /* nameserver port */
                     45: #endif
                     46: #ifndef        PACKETSZ
                     47: #define        PACKETSZ                512     /* maximum packet size */
                     48: #endif
                     49: 
                     50: static struct sockaddr_in *primary = 0, *secondary = 0;
                     51: 
                     52: /* currently we handle only following types of nameserver requests */
                     53: typedef        enum {
                     54:        IpAddress,      /* get A resource records */
                     55:        DomainName,     /* get PTR resource records */
                     56:        MailExchanger   /* get MX resource records */
                     57: } DomainType;
                     58: 
                     59: #define        MAX_EXPAND_TRIES        3 /* to resolve MX pointing to CNAME */
                     60: 
                     61: typedef        struct domain_transact_ent {
                     62:        /* caller supplied data */
                     63:        char *name;             /* original requested name (or ip address) */
                     64:        SESSION *sd;
                     65:        void (*callback)(SESSION *sd, DOMAIN_DATA *dd);
                     66: 
                     67:        /* request */
                     68:        u_short reqid;          /* request id */
                     69:        u_short expand;         /* expand MX pointing to CNAME */
                     70:        int retry;              /* retry counter */
                     71:        char *domain;           /* actual domain name requested */
                     72:        DomainType type;        /* type of request */
                     73: 
                     74:        /* response */
                     75:        int rcode;              /* nameserver reply code */
                     76:        DOMAIN_DATA *data;      /* list of answered data */
                     77: 
                     78:        struct domain_transact_ent *next;
                     79: } DOMAIN_TRANSACT;
                     80: 
                     81: #define        TRANSACT(sd)    ((DOMAIN_TRANSACT *)session_cookie(sd))
                     82: 
                     83: static DOMAIN_TRANSACT *first_transact = 0;
                     84: static DOMAIN_TRANSACT *new_transact();
                     85: static DOMAIN_TRANSACT *find_transact(u_short reqid);
                     86: static void free_transact(DOMAIN_TRANSACT *dt);
                     87: static DOMAIN_TRANSACT *parse_packet(const unsigned char *data, int len);
                     88: 
                     89: static void nameserver_error(SESSION *sd, int error);
                     90: static void nameserver_close(SESSION *sd);
                     91: static void nameserver_reply(SESSION *sd, const unsigned char *data, int len);
                     92: static int nameserver_request(const char *domain, DomainType type,
                     93:                              SESSION *org,
                     94:                              void (*notify)(SESSION *sd, DOMAIN_DATA *dd));
                     95: static int nameserver_send(SESSION *sd);
                     96: static void discard_request(void *arg); /* (DOMAIN_TRANSACT *) */
                     97: static u_short unique_reqid();
                     98: 
                     99: #ifdef HAVE_REPORT_FUNC
                    100: static const char *rcode2text[6] = {
                    101:  "No error",           /* 0 - NOERROR */
                    102:  "Format error",       /* 1 - FORMERR */
                    103:  "Server failure",     /* 2 - SERVFAIL */
                    104:  "Non existend domain",        /* 3 - NXDOAMIN */
                    105:  "Not implemented",    /* 4 - NOTIMP */
                    106:  "Query refused"       /* 5 - REFUSED */
                    107: };
                    108: #endif
                    109: 
                    110: #ifdef DEBUG
                    111: void
                    112: dump_reply(dt)
                    113:        DOMAIN_TRANSACT *dt;
                    114: {
                    115:        DOMAIN_DATA *dd;
                    116:        char ipaddr[50];
                    117: 
                    118:        if (!dt) {
                    119:                printf("REPLY: domain transaction is null\n");
                    120:                return;
                    121:        }
                    122:        printf("REPLY: reqid=%d retry=%d domain=\"%s\" type=%d rcode=\"%s\"\n",
                    123:               dt->reqid, dt->retry, dt->domain, dt->type, rcode2text[dt->rcode]);
                    124:        for (dd = dt->data; dd; dd = dd->next) {
                    125:                printf("REPLY:\tttl=%u\tpref=%u\tname=\"%s\"\taddr=%s\n",
                    126:                       dd->ttl, dd->pref, dd->name, intoa(ipaddr, dd->addr));
                    127: 
                    128:        }
                    129: }
                    130: #endif
                    131: 
                    132: int
                    133: domain_resolver_init()
                    134: {
                    135:        FILE *fp;
                    136:        int ns_cnt = 0;
                    137:        char *cp, buf[1024];
                    138: 
                    139:        if (!primary) {
                    140:                primary = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
                    141:                if (!primary) return -1;
                    142:        }
                    143:        memset(primary, 0, sizeof(struct sockaddr_in));
                    144:        primary->sin_family = AF_INET;
                    145:        primary->sin_port = htons(NAMESERVER_PORT);
                    146:        primary->sin_addr.s_addr = htonl(0x7f000001);/* 127.0.0.1 by default */
                    147: 
                    148:        if (secondary) {
                    149:                free(secondary);
                    150:                secondary = 0;
                    151:        }
                    152: 
                    153:        if ((fp = fopen(_PATH_RESCONF, "r")) != 0) {
                    154:                while (fgets(buf, sizeof(buf), fp) != 0) {
                    155:                        buf[sizeof(buf)-1] = '\0';
                    156:                        for (cp = buf; *cp; cp++) {
                    157:                                if (*cp == '#' || *cp == '\r' || *cp == '\n') {
                    158:                                        *cp = '\0';
                    159:                                        break;
                    160:                                }
                    161:                                if (*cp < ' ') *cp = ' ';
                    162:                        }
                    163:                        if (buf[0] == '\0')
                    164:                                continue; /* skip empty lines and commentary */
                    165: 
                    166:                        if (!strncasecmp(buf, NAMESERVER_TOKEN, sizeof(NAMESERVER_TOKEN)-1)) {
                    167:                                cp = strip_blanks(buf + sizeof(NAMESERVER_TOKEN)-1);
                    168:                                if (!ns_cnt++) {
                    169:                                        primary->sin_addr.s_addr = inet_addr(cp);
                    170:                                } else if (!secondary) {
                    171:                                        secondary = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
                    172:                                        if (secondary) {
                    173:                                                memset(secondary, 0, sizeof(struct sockaddr_in));
                    174:                                                secondary->sin_family = AF_INET;
                    175:                                                secondary->sin_port = htons(NAMESERVER_PORT);
                    176:                                                secondary->sin_addr.s_addr = inet_addr(cp);
                    177:                                        }
                    178:                                }
                    179:                        }
                    180:                }
                    181:                (void)fclose(fp);
                    182:        }
                    183:        return ns_cnt;
                    184: }
                    185: 
                    186: int
                    187: domain_resolve_addr(domain, sd, notify)
                    188:        const char *domain;
                    189:        SESSION *sd;
                    190:        void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
                    191: {
                    192:        return nameserver_request(domain, IpAddress, sd, notify);
                    193: }
                    194: 
                    195: int
                    196: domain_resolve_mxlist(domain, sd, notify)
                    197:        const char *domain;
                    198:        SESSION *sd;
                    199:        void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
                    200: {
                    201:        return nameserver_request(domain, MailExchanger, sd, notify);
                    202: }
                    203: 
                    204: int
                    205: domain_resolve_name(ipaddr, sd, notify)
                    206:        in_addr_t ipaddr;
                    207:        SESSION *sd;
                    208:        void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
                    209: {
                    210:        return nameserver_request((char *)&ipaddr, DomainName, sd, notify);
                    211: }
                    212: 
                    213: 
                    214: /*
                    215:  * Callback function: catch all errors during nameserver request.
                    216:  */
                    217: static void
                    218: nameserver_error(sd, error)
                    219:        SESSION *sd;
                    220:        int error;
                    221: {
                    222:        DOMAIN_TRANSACT *dt = TRANSACT(sd);
                    223:        if (sd && dt) {
                    224:                if (error != ETIMEDOUT) {
                    225: #ifdef HAVE_REPORT_FUNC
                    226:                        report(Warn, 0, error, "%lu: domain_resolver: %s (try=%d)",
                    227:                               sd->sid, peertoa(0, session_peer(sd)),
                    228:                               dt->retry + 1);
                    229: #endif
                    230:                } else if (++dt->retry < NAMESERVER_RETRIES) {
                    231:                        nameserver_send(sd);
                    232:                        return;
                    233:                }
                    234:        }
                    235:        nameserver_close(sd);
                    236: }
                    237: 
                    238: /*
                    239:  * Normal close nameserver request.
                    240:  */
                    241: static void
                    242: nameserver_close(sd)
                    243:        SESSION *sd;
                    244: {
                    245:        DOMAIN_TRANSACT *dt = TRANSACT(sd);
                    246: 
                    247:        session_free(sd);
                    248:        if (dt) {
                    249:                if (dt->data) { /* purge unresolved names */
                    250:                        if (dt->type != DomainName)
                    251:                                domain_data_free(&dt->data, "");
                    252:                        else if (dt->data->addr == 0 || dt->data->addr == -1)
                    253:                                memcpy(&dt->data->addr, dt->name, sizeof(dt->data->addr));
                    254:                }
                    255: #ifdef DEBUG
                    256:                dump_reply(dt);
                    257: #endif
                    258:                if (dt->callback) {
                    259:                        (*dt->callback)(dt->sd, dt->data);
                    260:                        dt->data = 0; /* received data dispatched */
                    261:                }
                    262:                free_transact(dt);
                    263:        }
                    264: }
                    265: 
                    266: static void
                    267: discard_request(arg)
                    268:        void *arg;
                    269: {
                    270:        DOMAIN_TRANSACT *dt = (DOMAIN_TRANSACT *)arg;
                    271:        if (dt) {
                    272:                dt->sd = 0;
                    273:                dt->callback = 0;
                    274:        }
                    275: }
                    276: 
                    277: static u_short
                    278: unique_reqid()
                    279: {
                    280:        static u_short reqid = 0;
                    281:        if (++reqid == 0) reqid++; /* prevent 0 reqid */
                    282:        return reqid;
                    283: }
                    284: 
                    285: static DOMAIN_TRANSACT *
                    286: new_transact()
                    287: {
                    288:        DOMAIN_TRANSACT *curr;
                    289:        if ((curr = (DOMAIN_TRANSACT *)malloc(sizeof(DOMAIN_TRANSACT))) == 0)
                    290:                return 0;
                    291:        memset(curr, 0, sizeof(DOMAIN_TRANSACT));
                    292: 
                    293:        if (first_transact) {
                    294:                DOMAIN_TRANSACT *prev = first_transact;
                    295:                while (prev->next) prev = prev->next;
                    296:                prev->next = curr;
                    297:        } else  first_transact = curr;
                    298: 
                    299:        return curr;
                    300: }
                    301: 
                    302: static DOMAIN_TRANSACT *
                    303: find_transact(reqid)
                    304:        u_short reqid;
                    305: {
                    306:        DOMAIN_TRANSACT *curr;
                    307:        for (curr = first_transact; curr; curr = curr->next) {
                    308:                if (curr->reqid && curr->reqid == reqid)
                    309:                        return curr;
                    310:        }
                    311:        return 0;
                    312: }
                    313: 
                    314: static void
                    315: free_transact(dt)
                    316:        DOMAIN_TRANSACT *dt;
                    317: {
                    318:        DOMAIN_TRANSACT *curr, *prev, *next;
                    319: 
                    320:        curr = first_transact;
                    321:        prev = 0;
                    322:        while (curr) {
                    323:                if (!dt || curr == dt) {
                    324:                        next = curr->next;
                    325:                        if (prev)
                    326:                                prev->next = next;
                    327:                        else    first_transact = next;
                    328: 
                    329:                        if (curr->sd)
                    330:                                session_unbind(curr->sd, discard_request, curr);
                    331:                        if (curr->name)
                    332:                                free(curr->name);
                    333:                        if (curr->domain)
                    334:                                free(curr->domain);
                    335:                        domain_data_free(&curr->data, 0);
                    336:                        free(curr);
                    337: 
                    338:                        curr = next;
                    339:                } else {
                    340:                        prev = curr;
                    341:                        curr = curr->next;
                    342:                }
                    343:        }
                    344: }
                    345: 
                    346: DOMAIN_DATA *
                    347: domain_data_add(list, name, pref)
                    348:        DOMAIN_DATA **list;
                    349:        const char *name;
                    350:        int pref;
                    351: {
                    352:        DOMAIN_DATA *curr, *last, *prev;
                    353:        int insert;
                    354:        char *cp;
                    355: 
                    356:        /* sanity check */
                    357:        if (!list || !name || !*name) {
                    358:                errno = EINVAL;
                    359:                return 0;
                    360:        }
                    361: 
                    362:        /* sort it by pref ascending (bigger pref farther) */
                    363:        last = prev = 0;
                    364:        insert = 0;
                    365:        for (curr = *list; curr; curr = curr->next) {
                    366:                /* prevent duplicates */
                    367:                if (curr->name && !strcasecmp(curr->name, name))
                    368:                        return curr;
                    369: 
                    370:                if (!insert && pref < curr->pref) {
                    371:                        insert++;
                    372:                        prev = last;
                    373:                }
                    374:                last = curr;
                    375:        }
                    376:        if ((curr = (DOMAIN_DATA *)malloc(sizeof(DOMAIN_DATA))) == 0)
                    377:                return 0;
                    378:        memset(curr, 0, sizeof(DOMAIN_DATA));
                    379: 
                    380:        if ((curr->name = strdup(name)) == 0) {
                    381:                int save_errno = errno;
                    382:                free(curr);
                    383:                save_errno = errno;
                    384:                return 0;
                    385:        }
                    386:        /* make all lowercase */
                    387:        for (cp = curr->name; *cp; cp++) {
                    388:                if (*cp >= 'A' && *cp <= 'Z')
                    389:                        *cp = *cp + 32;
                    390:        }
                    391:        curr->pref = pref;
                    392: 
                    393:        if (insert) {
                    394:                if (prev) {
                    395:                        curr->next = prev->next;
                    396:                        prev->next = curr;
                    397:                } else {
                    398:                        curr->next = *list;
                    399:                        *list = curr;
                    400:                }
                    401:        } else if (last) {
                    402:                last->next = curr;
                    403:        } else {
                    404:                *list = curr;
                    405:        }
                    406:        return curr;
                    407: }
                    408: 
                    409: DOMAIN_DATA *
                    410: domain_data_find(list, name)
                    411:        DOMAIN_DATA **list;
                    412:        const char *name;
                    413: {
                    414:        DOMAIN_DATA *curr;
                    415: 
                    416:        /* sanity check */
                    417:        if (!list || !name || !*name)
                    418:                return 0;
                    419: 
                    420:        for (curr = *list; curr; curr = curr->next) {
                    421:                if (!strcasecmp(curr->name, name))
                    422:                        return curr;
                    423:        }
                    424:        return 0;
                    425: }
                    426: 
                    427: void
                    428: domain_data_free(list, name)
                    429:        DOMAIN_DATA **list;
                    430:        const char *name;
                    431: {
                    432:        DOMAIN_DATA *curr, *prev, *next;
                    433: 
                    434:        /* sanity check */
                    435:        if (!list) return;
                    436: 
                    437:        curr = *list;
                    438:        prev = 0;
                    439:        while (curr) {
                    440:                if (!name || (*name == '\0' && curr->addr == 0) ||
                    441:                    curr->name == name || !strcasecmp(curr->name, name)) {
                    442:                        next = curr->next;
                    443:                        if (prev)
                    444:                                prev->next = next;
                    445:                        else    *list = next;
                    446: 
                    447:                        if (curr->name) free(curr->name);
                    448:                        free(curr);
                    449: 
                    450:                        curr = next;
                    451:                } else {
                    452:                        prev = curr;
                    453:                        curr = curr->next;
                    454:                }
                    455:        }
                    456: }
                    457: 
                    458: static int
                    459: nameserver_request(domain, type, org, notify)
                    460:        const char *domain;
                    461:        DomainType type;
                    462:        SESSION *org;
                    463:        void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
                    464: {
                    465:        SESSION *sd;
                    466:        DOMAIN_TRANSACT *dt;
                    467:        char buf[MAXDNAME];
                    468:        const u_char *cp;
                    469: 
                    470:        /* sanity check */
                    471:        if (!domain || !*domain) {
                    472:                errno = EINVAL;
                    473:                return -1;
                    474:        }
                    475:        if (!primary && domain_resolver_init() < 0)
                    476:                return -1;
                    477: 
                    478:        if ((sd = session_open(-1, (struct sockaddr *)primary, DataSequence)) == 0)
                    479:                return -1;
                    480: 
                    481:        if ((dt = new_transact()) == 0) {
                    482:                int save_errno = errno;
                    483:                session_free(sd);
                    484:                errno = save_errno;
                    485:                return -1;
                    486:        }
                    487:        switch (type) {
                    488:        case IpAddress:
                    489:        case MailExchanger:
                    490:                dt->name = strdup(domain);
                    491:                (void)strncpy(buf, domain, sizeof(buf));
                    492:                buf[sizeof(buf)-1] = '\0';
                    493:                dt->domain = strdup(buf);
                    494:                break;
                    495:        case DomainName:
                    496:                if ((dt->name = (char *)malloc(sizeof(in_addr_t))) == 0)
                    497:                        break;
                    498:                memcpy(dt->name, domain, sizeof(in_addr_t));
                    499:                cp = (u_char *)domain;
                    500:                snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
                    501:                         cp[3], cp[2], cp[1], cp[0]);
                    502:                dt->domain = strdup(buf);
                    503:                break;
                    504:        }
                    505:        if (!dt->name || !dt->domain) {
                    506:                int save_errno = errno;
                    507:                session_free(sd);
                    508:                free_transact(dt);
                    509:                errno = save_errno;
                    510:                return -1;
                    511:        }
                    512:        dt->reqid = unique_reqid();
                    513:        dt->type = type;
                    514: 
                    515:        session_setcallback(sd, 0, nameserver_error, nameserver_reply);
                    516:        session_setcookie(sd, dt);
                    517:        session_settimeout(sd, NAMESERVER_TIMEOUT);
                    518: 
                    519:        if (nameserver_send(sd) < 0) {
                    520:                int save_errno = errno;
                    521: #ifdef HAVE_REPORT_FUNC
                    522:                char ipaddr[50];
                    523:                report(Warn, 0, errno, "%lu: nameserver_send: %s",
                    524:                       sd->sid, peertoa(ipaddr, session_peer(sd)));
                    525: #endif
                    526:                session_free(sd);
                    527:                free_transact(dt);
                    528:                errno = save_errno;
                    529:                return -1;
                    530:        }
                    531:        if (org && session_bind(org, discard_request, dt) != -1)
                    532:                dt->sd = org;
                    533:        dt->callback = notify;
                    534:        return 0;
                    535: }
                    536: 
                    537: static int
                    538: nameserver_send(sd)
                    539:        SESSION *sd;
                    540: {
                    541:        DOMAIN_TRANSACT *dt = TRANSACT(sd);
                    542:        u_char buf[PACKETSZ];
                    543:        HEADER *hp = (HEADER *)buf;
                    544:        int len;
                    545:        u_char *cp, *dnptrs[50], **dpp, **lastdnptr;
                    546: 
                    547:        /* sanity check */
                    548:        if (!dt) {
                    549:                errno = EINVAL;
                    550:                return -1;
                    551:        }
                    552:        memset(hp, 0, HFIXEDSZ);
                    553:        hp->id = htons(dt->reqid);
                    554:        hp->rd = 1; /* recursion desired */
                    555:        hp->qdcount = htons(1); /* we allways utilize one query per packet */
                    556: 
                    557:        cp = buf + HFIXEDSZ;
                    558:        len = PACKETSZ - (HFIXEDSZ + QFIXEDSZ);
                    559:        dpp = dnptrs;
                    560:        *dpp++ = buf;
                    561:        *dpp = 0;
                    562:        lastdnptr = dnptrs + sizeof(dnptrs) / sizeof(dnptrs[0]);
                    563: 
                    564:        if ((len = dn_comp(dt->domain, cp, len, dnptrs, lastdnptr)) < 0)
                    565:                return -1;
                    566: 
                    567:        cp += len;
                    568:        /* translate our type into appropriate NS opcode && type */
                    569:        switch (dt->type) {
                    570:        case IpAddress:
                    571:                PUTSHORT(T_A, cp);
                    572:                break;
                    573:        case DomainName:
                    574:                PUTSHORT(T_PTR, cp);
                    575:                break;
                    576:        case MailExchanger:
                    577:                PUTSHORT(T_MX, cp);
                    578:                break;
                    579:        }
                    580:        PUTSHORT(C_IN, cp);
                    581:        len = cp - buf;
                    582: 
                    583:        dprintf(("nameserver_send: \"%s\"", dt->domain));
                    584: 
                    585:        return session_send(sd, buf, len);
                    586: }
                    587: 
                    588: static void
                    589: nameserver_reply(sd, data, len)
                    590:        SESSION *sd;
                    591:        const unsigned char *data;
                    592:        int len;
                    593: {
                    594:        DOMAIN_TRANSACT *dt;
                    595: 
                    596:        /* sanity check */
                    597:        if (!sd) return;
                    598: 
                    599:        if ((dt = parse_packet(data, len)) == 0) {
                    600: #ifdef HAVE_REPORT_FUNC
                    601:                char ipaddr[50];
                    602:                report(Info, 0, 0, "%lu: nameserver_reply: %s: unexpected packet (len=%d)",
                    603:                       sd->sid, peertoa(ipaddr, session_peer(sd)), len);
                    604: #endif
                    605:                return;
                    606:        }
                    607:        if (dt->rcode < 0) {
                    608: #ifdef HAVE_REPORT_FUNC
                    609:                char ipaddr[50];
                    610:                report(Info, 0, 0, "%lu: nameserver_reply: %s: broken packet (len=%d try=%d err=%d)",
                    611:                       sd->sid, peertoa(ipaddr, session_peer(sd)),
                    612:                       len, dt->retry + 1, -dt->rcode);
                    613: #endif
                    614:                return;
                    615:        }
                    616: #ifdef HAVE_REPORT_FUNC
                    617:        if (dt->rcode != NOERROR &&
                    618:            dt->rcode != SERVFAIL &&
                    619:            dt->rcode != NXDOMAIN) {
                    620:                char ipaddr[50];
                    621:                report(Crit, 0, 0, "%lu: nameserver_reply: %s: %s (try=%d)",
                    622:                       sd->sid, peertoa(ipaddr, session_peer(sd)),
                    623:                       rcode2text[dt->rcode], dt->retry + 1);
                    624:        }
                    625: #endif
                    626: #ifdef DEBUG
                    627:        dump_reply(dt);
                    628: #endif
                    629:        if (dt->rcode == NOERROR &&
                    630:            (dt->type == MailExchanger ||
                    631:             (dt->type == IpAddress && dt->expand && dt->expand < MAX_EXPAND_TRIES))) {
                    632:                DOMAIN_DATA *dd;
                    633:                for (dd = dt->data; dd; dd = dd->next) {
                    634:                        /* it was CNAME -- expand it */
                    635:                        if (dd->name && !dd->addr) {
                    636:                                if (dt->domain) {
                    637:                                        if (!strcasecmp(dd->name, dt->domain))
                    638:                                                break; /* to prevent looping */
                    639:                                        free(dt->domain);
                    640:                                }
                    641:                                if ((dt->domain = strdup(dd->name)) == 0)
                    642:                                        break;
                    643:                                dt->reqid = unique_reqid();
                    644:                                dt->expand++;
                    645:                                dt->retry = 0;
                    646:                                dt->type = IpAddress;
                    647:                                if (nameserver_send(sd) < 0)
                    648:                                        break;
                    649:                                return;
                    650:                        }
                    651:                }
                    652:        }
                    653:        nameserver_close(sd); /* caller notified inside */
                    654: }
                    655: 
                    656: static DOMAIN_TRANSACT *
                    657: parse_packet(data, len)
                    658:        const unsigned char *data;
                    659:        int len;
                    660: {
                    661:        const u_char *pkt = data;
                    662:        HEADER *hp = (HEADER *)pkt;
                    663:        const u_char *cp = pkt + HFIXEDSZ;
                    664:        int qdcount, ancount, nscount, arcount, nb;
                    665:        DOMAIN_TRANSACT *dt;
                    666:        DOMAIN_DATA *dd;
                    667:        u_short type, class, rdlen, pref;
                    668:        u_int ttl;
                    669:        char name[MAXDNAME+1];
                    670: 
                    671:        /*
                    672:         * first check the response Header.
                    673:         */
                    674:        if (!hp || len < HFIXEDSZ) {
                    675:                dprintf(("parse_packet: undersized packet, len=%d", len));
                    676:                return 0;
                    677:        }
                    678:        if (!hp->qr) {
                    679:                dprintf(("parse_packet: not a response"));
                    680:                return 0;
                    681:        }
                    682:        if (hp->opcode) {
                    683:                dprintf(("parse_packet: response not a QUERY"));
                    684:                return 0;
                    685:        }
                    686:        if (hp->rcode < NOERROR || hp->rcode > REFUSED) {
                    687:                dprintf(("parse_packet: bad reply code %d", (int)hp->rcode));
                    688:                return 0;
                    689:        }
                    690:        if ((dt = find_transact(ntohs(hp->id))) == 0) {
                    691:                dprintf(("parse_packet: invalid reqid"));
                    692:                return 0;
                    693:        }
                    694:        dt->rcode = hp->rcode; /* Header is OK; reply code fixed */
                    695: 
                    696:        qdcount = ntohs(hp->qdcount);
                    697:        ancount = ntohs(hp->ancount);
                    698:        nscount = ntohs(hp->nscount);
                    699:        arcount = ntohs(hp->arcount);
                    700: 
                    701:        dprintf(("parse_packet: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d",
                    702:                 hp->rcode, qdcount, ancount, nscount, arcount));
                    703: 
                    704:        /*
                    705:         * check Question section.
                    706:         */
                    707:        while (qdcount-- > 0) {
                    708:                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    709:                        dprintf(("parse_packet: dn_expand: unexpected end of question"));
                    710:                        dt->rcode = -1;
                    711:                        return dt;
                    712:                }
                    713:                if (strcasecmp(name, dt->domain)) {
                    714:                        dprintf(("parse_packet: question name mismatch transaction"));
                    715:                        dt->rcode = -2;
                    716:                        return dt;
                    717:                }
                    718:                cp += nb;
                    719:                if (cp + 2 * INT16SZ > pkt + len) {
                    720:                        dprintf(("parse_packet: unexpected end of question"));
                    721:                        dt->rcode = -3;
                    722:                        return dt;
                    723:                }
                    724:                GETSHORT(type, cp);
                    725:                GETSHORT(class, cp);
                    726:                if (class != C_IN) {
                    727:                        dprintf(("parse_packet: question class mismatch transaction"));
                    728:                        dt->rcode = -4;
                    729:                        return dt;
                    730:                }
                    731:                if ((type == T_A && dt->type == IpAddress) ||
                    732:                    (type == T_PTR && dt->type == DomainName) ||
                    733:                    (type == T_MX && dt->type == MailExchanger))
                    734:                        continue;
                    735: 
                    736:                dprintf(("parse_packet: question type mismatch transaction"));
                    737:                dt->rcode = -5;
                    738:                return dt;
                    739:        }
                    740: 
                    741:        /*
                    742:         * parse Answer section.
                    743:         */
                    744:        while (ancount-- > 0) {
                    745:                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    746:                        dprintf(("parse_packet: dn_expand: unexpected end of answer"));
                    747:                        dt->rcode = -10;
                    748:                        return dt;
                    749:                }
                    750:                dprintf(("parse_packet: answer name \"%s\"", name));
                    751:                cp += nb;
                    752:                if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
                    753:                        dprintf(("parse_packet: unexpected end of answer"));
                    754:                        dt->rcode = -11;
                    755:                        return dt;
                    756:                }
                    757:                GETSHORT(type, cp);
                    758:                GETSHORT(class, cp);
                    759:                GETLONG(ttl, cp);
                    760:                GETSHORT(rdlen, cp);
                    761:                if (cp + rdlen > pkt + len) {
                    762:                        dprintf(("parse_packet: unexpected end of answer"));
                    763:                        dt->rcode = -12;
                    764:                        return dt;
                    765:                }
                    766:                if (class != C_IN) {
                    767:                        dprintf(("parse_packet: answer class mismatch transaction"));
                    768:                        dt->rcode = -13;
                    769:                        return dt;
                    770:                }
                    771:                dprintf(("parse_packet: answer rdlen=%d", rdlen));
                    772: 
                    773:                if (type == T_A && dt->type == IpAddress) {
                    774:                        /* XXX IPv6 incompatible yet */
                    775:                        if (rdlen % sizeof(in_addr_t)) {
                    776:                                dprintf(("parse_packet: unexpected rdlen in A RR"));
                    777:                                dt->rcode = -14;
                    778:                                return dt;
                    779:                        }
                    780:                        while (rdlen > 0) {
                    781:                                dprintf(("parse_packet: A %d.%d.%d.%d (ttl=%d)",
                    782:                                         cp[0], cp[1], cp[2], cp[3], ttl));
                    783:                                if ((dd = domain_data_add(&dt->data, name, 0)) != 0) {
                    784:                                        if (!dd->ttl || !ttl || dd->ttl > ttl)
                    785:                                                dd->ttl = ttl;
                    786:                                        if (dd->addr == 0 || dd->addr == -1)
                    787:                                                dd->addr = *((in_addr_t *)cp);
                    788:                                }
                    789:                                cp += sizeof(in_addr_t);
                    790:                                rdlen -= sizeof(in_addr_t);
                    791:                        }
                    792:                        continue;
                    793:                }
                    794:                if (type == T_MX && dt->type == MailExchanger) {
                    795:                        if (rdlen < INT16SZ) {
                    796:                                dprintf(("parse_packet: unexpected rdlen in MX RR"));
                    797:                                dt->rcode = -15;
                    798:                                return dt;
                    799:                        }
                    800:                        GETSHORT(pref, cp);
                    801:                        rdlen -= INT16SZ;
                    802:                        while (rdlen > 0) {
                    803:                                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    804:                                        dprintf(("parse_packet: dn_expand: unexpected end of answer"));
                    805:                                        dt->rcode = -16;
                    806:                                        return dt;
                    807:                                }
                    808:                                dprintf(("parse_packet: MX %d \"%s\" (ttl=%d)",
                    809:                                         pref, name, ttl));
                    810:                                if ((dd = domain_data_add(&dt->data, name, pref)) != 0) {
                    811:                                        if (!dd->ttl || !ttl || dd->ttl > ttl)
                    812:                                                dd->ttl = ttl;
                    813:                                }
                    814:                                cp += nb;
                    815:                                rdlen -= nb;
                    816:                        }
                    817:                        continue;
                    818:                }
                    819:                if (type == T_PTR && dt->type == DomainName) {
                    820:                        while (rdlen > 0) {
                    821:                                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    822:                                        dprintf(("parse_packet: dn_expand: unexpected end of answer"));
                    823:                                        dt->rcode = -17;
                    824:                                        return dt;
                    825:                                }
                    826:                                dprintf(("parse_packet: PTR \"%s\" (ttl=%d)",
                    827:                                         name, ttl));
                    828:                                if ((dd = domain_data_add(&dt->data, name, 0)) != 0) {
                    829:                                        if (!dd->ttl || !ttl || dd->ttl > ttl)
                    830:                                                dd->ttl = ttl;
                    831:                                }
                    832:                                cp += nb;
                    833:                                rdlen -= nb;
                    834:                        }
                    835:                        continue;
                    836:                }
                    837:                if (type == T_CNAME) {
                    838:                        dprintf(("parse_packet: CNAME \"%s\" removed", name));
                    839:                        domain_data_free(&dt->data, name);
                    840:                        cp += rdlen;
                    841:                        continue;
                    842:                }
                    843:                /* simply skip it */
                    844:                dprintf(("parse_packet: answer name \"%s\" type %d",
                    845:                         name, type));
                    846:                cp += rdlen;
                    847:        }
                    848: 
                    849:        if (dt->type != MailExchanger)
                    850:                return dt;
                    851: 
                    852:        /*
                    853:         * skip Authority section.
                    854:         */
                    855:        while (nscount-- > 0) {
                    856:                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    857:                        dprintf(("parse_packet: dn_expand: unexpected end of authority"));
                    858:                        dt->rcode = -20;
                    859:                        return dt;
                    860:                }
                    861:                cp += nb;
                    862:                if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
                    863:                        dprintf(("parse_packet: unexpected end of authority"));
                    864:                        dt->rcode = -21;
                    865:                        return dt;
                    866:                }
                    867:                GETSHORT(type, cp);
                    868:                GETSHORT(class, cp);
                    869:                GETLONG(ttl, cp);
                    870:                GETSHORT(rdlen, cp);
                    871:                if (cp + rdlen > pkt + len) {
                    872:                        dprintf(("parse_packet: unexpected end of authority"));
                    873:                        dt->rcode = -22;
                    874:                        return dt;
                    875:                }
                    876:                /* simply skip it */
                    877:                dprintf(("parse_packet: authority name \"%s\" type %d",
                    878:                         name, type));
                    879:                cp += rdlen;
                    880:        }
                    881: 
                    882:        /*
                    883:         * parse Additional section.
                    884:         */
                    885:        while (arcount-- > 0) {
                    886:                if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
                    887:                        dprintf(("parse_packet: dn_expand: unexpected end of answer"));
                    888:                        dt->rcode = -30;
                    889:                        return dt;
                    890:                }
                    891:                dprintf(("parse_packet: additional name \"%s\"", name));
                    892:                cp += nb;
                    893:                if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
                    894:                        dprintf(("parse_packet: unexpected end of additional"));
                    895:                        dt->rcode = -31;
                    896:                        return dt;
                    897:                }
                    898:                GETSHORT(type, cp);
                    899:                GETSHORT(class, cp);
                    900:                GETLONG(ttl, cp);
                    901:                GETSHORT(rdlen, cp);
                    902:                if (cp + rdlen > pkt + len) {
                    903:                        dprintf(("parse_packet: unexpected end of additional"));
                    904:                        dt->rcode = -32;
                    905:                        return dt;
                    906:                }
                    907:                if (class == C_IN && type == T_A) {
                    908:                        /* XXX IPv6 incompatible yet */
                    909:                        if (rdlen % sizeof(in_addr_t)) {
                    910:                                dprintf(("parse_packet: unexpected rdlen in A RR"));
                    911:                                dt->rcode = -33;
                    912:                                return dt;
                    913:                        }
                    914:                        while (rdlen > 0) {
                    915:                                dprintf(("parse_packet: A %d.%d.%d.%d (ttl=%d)",
                    916:                                         cp[0], cp[1], cp[2], cp[3], ttl));
                    917:                                if ((dd = domain_data_find(&dt->data, name)) != 0) {
                    918:                                        if (!dd->ttl || !ttl || dd->ttl > ttl)
                    919:                                                dd->ttl = ttl;
                    920:                                        if (dd->addr == 0 || dd->addr == -1)
                    921:                                                dd->addr = *((in_addr_t *)cp);
                    922:                                }
                    923:                                cp += sizeof(in_addr_t);
                    924:                                rdlen -= sizeof(in_addr_t);
                    925:                        }
                    926:                        continue;
                    927:                }
                    928:                /* simply skip it */
                    929:                dprintf(("parse_packet: additional name \"%s\" type %d",
                    930:                         name, type));
                    931:                cp += rdlen;
                    932:        }
                    933: 
                    934:        return dt;
                    935: }
                    936: 

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