[BACK]Return to nslookup.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / dig

Annotation of src/usr.bin/dig/nslookup.c, Revision 1.10

1.1       florian     1: /*
                      2:  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
                      3:  *
                      4:  * Permission to use, copy, modify, and/or distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                      9:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     10:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     11:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     12:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     13:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     14:  * PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16:
                     17: #include <limits.h>
                     18: #include <stdlib.h>
                     19: #include <string.h>
                     20: #include <unistd.h>
                     21:
                     22: #include <isc/app.h>
                     23: #include <isc/buffer.h>
                     24: #include <isc/event.h>
                     25: #include <isc/util.h>
                     26: #include <isc/task.h>
                     27:
                     28: #include <dns/message.h>
                     29: #include <dns/name.h>
                     30: #include <dns/fixedname.h>
                     31: #include <dns/rdata.h>
                     32: #include <dns/rdataclass.h>
                     33: #include <dns/rdataset.h>
                     34: #include <dns/rdatatype.h>
                     35:
                     36: #include "dig.h"
                     37:
                     38: static isc_boolean_t short_form = ISC_TRUE,
                     39:        tcpmode = ISC_FALSE,
                     40:        identify = ISC_FALSE, stats = ISC_TRUE,
                     41:        comments = ISC_TRUE, section_question = ISC_TRUE,
                     42:        section_answer = ISC_TRUE, section_authority = ISC_TRUE,
                     43:        section_additional = ISC_TRUE, recurse = ISC_TRUE,
                     44:        aaonly = ISC_FALSE, nofail = ISC_TRUE;
                     45:
                     46: static isc_boolean_t interactive;
                     47:
                     48: static isc_boolean_t in_use = ISC_FALSE;
                     49: static char defclass[MXRD] = "IN";
                     50: static char deftype[MXRD] = "A";
                     51: static isc_event_t *global_event = NULL;
                     52: static int query_error = 1, print_error = 0;
                     53:
                     54: static char domainopt[DNS_NAME_MAXTEXT];
                     55:
                     56: static const char *rcodetext[] = {
                     57:        "NOERROR",
                     58:        "FORMERR",
                     59:        "SERVFAIL",
                     60:        "NXDOMAIN",
                     61:        "NOTIMP",
                     62:        "REFUSED",
                     63:        "YXDOMAIN",
                     64:        "YXRRSET",
                     65:        "NXRRSET",
                     66:        "NOTAUTH",
                     67:        "NOTZONE",
                     68:        "RESERVED11",
                     69:        "RESERVED12",
                     70:        "RESERVED13",
                     71:        "RESERVED14",
                     72:        "RESERVED15",
                     73:        "BADVERS"
                     74: };
                     75:
                     76: static const char *rtypetext[] = {
                     77:        "rtype_0 = ",                   /* 0 */
                     78:        "internet address = ",          /* 1 */
                     79:        "nameserver = ",                /* 2 */
                     80:        "md = ",                        /* 3 */
                     81:        "mf = ",                        /* 4 */
                     82:        "canonical name = ",            /* 5 */
                     83:        "soa = ",                       /* 6 */
                     84:        "mb = ",                        /* 7 */
                     85:        "mg = ",                        /* 8 */
                     86:        "mr = ",                        /* 9 */
                     87:        "rtype_10 = ",                  /* 10 */
                     88:        "protocol = ",                  /* 11 */
                     89:        "name = ",                      /* 12 */
                     90:        "hinfo = ",                     /* 13 */
                     91:        "minfo = ",                     /* 14 */
                     92:        "mail exchanger = ",            /* 15 */
                     93:        "text = ",                      /* 16 */
                     94:        "rp = ",                        /* 17 */
                     95:        "afsdb = ",                     /* 18 */
                     96:        "x25 address = ",               /* 19 */
                     97:        "isdn address = ",              /* 20 */
                     98:        "rt = ",                        /* 21 */
                     99:        "nsap = ",                      /* 22 */
                    100:        "nsap_ptr = ",                  /* 23 */
                    101:        "signature = ",                 /* 24 */
                    102:        "key = ",                       /* 25 */
                    103:        "px = ",                        /* 26 */
                    104:        "gpos = ",                      /* 27 */
                    105:        "has AAAA address ",            /* 28 */
                    106:        "loc = ",                       /* 29 */
                    107:        "next = ",                      /* 30 */
                    108:        "rtype_31 = ",                  /* 31 */
                    109:        "rtype_32 = ",                  /* 32 */
                    110:        "service = ",                   /* 33 */
                    111:        "rtype_34 = ",                  /* 34 */
                    112:        "naptr = ",                     /* 35 */
                    113:        "kx = ",                        /* 36 */
                    114:        "cert = ",                      /* 37 */
                    115:        "v6 address = ",                /* 38 */
                    116:        "dname = ",                     /* 39 */
                    117:        "rtype_40 = ",                  /* 40 */
                    118:        "optional = "                   /* 41 */
                    119: };
                    120:
                    121: #define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
                    122:
                    123: static void flush_lookup_list(void);
                    124: static void getinput(isc_task_t *task, isc_event_t *event);
                    125:
                    126: static char *
                    127: rcode_totext(dns_rcode_t rcode)
                    128: {
                    129:        static char buf[sizeof("?65535")];
                    130:        union {
                    131:                const char *consttext;
                    132:                char *deconsttext;
                    133:        } totext;
                    134:
                    135:        if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
                    136:                snprintf(buf, sizeof(buf), "?%u", rcode);
                    137:                totext.deconsttext = buf;
                    138:        } else
                    139:                totext.consttext = rcodetext[rcode];
                    140:        return totext.deconsttext;
                    141: }
                    142:
                    143: static void
                    144: query_finished(void) {
                    145:        isc_event_t *event = global_event;
                    146:
                    147:        flush_lookup_list();
                    148:        debug("dighost_shutdown()");
                    149:
                    150:        if (!in_use) {
                    151:                isc_app_shutdown();
                    152:                return;
                    153:        }
                    154:
                    155:        isc_task_send(global_task, &event);
                    156: }
                    157:
                    158: static void
                    159: printsoa(dns_rdata_t *rdata) {
                    160:        dns_rdata_soa_t soa;
                    161:        isc_result_t result;
                    162:        char namebuf[DNS_NAME_FORMATSIZE];
                    163:
1.7       florian   164:        result = dns_rdata_tostruct_soa(rdata, &soa);
                    165:        check_result(result, "dns_rdata_tostruct_soa");
1.1       florian   166:
                    167:        dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
                    168:        printf("\torigin = %s\n", namebuf);
                    169:        dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
                    170:        printf("\tmail addr = %s\n", namebuf);
                    171:        printf("\tserial = %u\n", soa.serial);
                    172:        printf("\trefresh = %u\n", soa.refresh);
                    173:        printf("\tretry = %u\n", soa.retry);
                    174:        printf("\texpire = %u\n", soa.expire);
                    175:        printf("\tminimum = %u\n", soa.minimum);
1.6       florian   176:        dns_rdata_freestruct_soa(&soa);
1.1       florian   177: }
                    178:
                    179: static void
                    180: printa(dns_rdata_t *rdata) {
                    181:        isc_result_t result;
                    182:        char text[sizeof("255.255.255.255")];
                    183:        isc_buffer_t b;
                    184:
                    185:        isc_buffer_init(&b, text, sizeof(text));
                    186:        result = dns_rdata_totext(rdata, NULL, &b);
                    187:        check_result(result, "dns_rdata_totext");
                    188:        printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
                    189:               (char *)isc_buffer_base(&b));
                    190: }
                    191: static void
                    192: printrdata(dns_rdata_t *rdata) {
                    193:        isc_result_t result;
                    194:        isc_buffer_t *b = NULL;
                    195:        unsigned int size = 1024;
                    196:        isc_boolean_t done = ISC_FALSE;
                    197:
                    198:        if (rdata->type < N_KNOWN_RRTYPES)
                    199:                printf("%s", rtypetext[rdata->type]);
                    200:        else
                    201:                printf("rdata_%d = ", rdata->type);
                    202:
                    203:        while (!done) {
                    204:                result = isc_buffer_allocate(&b, size);
                    205:                if (result != ISC_R_SUCCESS)
                    206:                        check_result(result, "isc_buffer_allocate");
                    207:                result = dns_rdata_totext(rdata, NULL, b);
                    208:                if (result == ISC_R_SUCCESS) {
                    209:                        printf("%.*s\n", (int)isc_buffer_usedlength(b),
                    210:                               (char *)isc_buffer_base(b));
                    211:                        done = ISC_TRUE;
                    212:                } else if (result != ISC_R_NOSPACE)
                    213:                        check_result(result, "dns_rdata_totext");
                    214:                isc_buffer_free(&b);
                    215:                size *= 2;
                    216:        }
                    217: }
                    218:
                    219: static isc_result_t
                    220: printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
                    221:             dns_section_t section) {
                    222:        isc_result_t result, loopresult;
                    223:        dns_name_t *name;
                    224:        dns_rdataset_t *rdataset = NULL;
                    225:        dns_rdata_t rdata = DNS_RDATA_INIT;
                    226:        char namebuf[DNS_NAME_FORMATSIZE];
                    227:
                    228:        UNUSED(query);
                    229:        UNUSED(headers);
                    230:
                    231:        debug("printsection()");
                    232:
                    233:        result = dns_message_firstname(msg, section);
                    234:        if (result == ISC_R_NOMORE)
                    235:                return (ISC_R_SUCCESS);
                    236:        else if (result != ISC_R_SUCCESS)
                    237:                return (result);
                    238:        for (;;) {
                    239:                name = NULL;
                    240:                dns_message_currentname(msg, section,
                    241:                                        &name);
                    242:                for (rdataset = ISC_LIST_HEAD(name->list);
                    243:                     rdataset != NULL;
                    244:                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
                    245:                        loopresult = dns_rdataset_first(rdataset);
                    246:                        while (loopresult == ISC_R_SUCCESS) {
                    247:                                dns_rdataset_current(rdataset, &rdata);
                    248:                                switch (rdata.type) {
                    249:                                case dns_rdatatype_a:
                    250:                                        if (section != DNS_SECTION_ANSWER)
                    251:                                                goto def_short_section;
                    252:                                        dns_name_format(name, namebuf,
                    253:                                                        sizeof(namebuf));
                    254:                                        printf("Name:\t%s\n", namebuf);
                    255:                                        printa(&rdata);
                    256:                                        break;
                    257:                                case dns_rdatatype_soa:
                    258:                                        dns_name_format(name, namebuf,
                    259:                                                        sizeof(namebuf));
                    260:                                        printf("%s\n", namebuf);
                    261:                                        printsoa(&rdata);
                    262:                                        break;
                    263:                                default:
                    264:                                def_short_section:
                    265:                                        dns_name_format(name, namebuf,
                    266:                                                        sizeof(namebuf));
                    267:                                        printf("%s\t", namebuf);
                    268:                                        printrdata(&rdata);
                    269:                                        break;
                    270:                                }
                    271:                                dns_rdata_reset(&rdata);
                    272:                                loopresult = dns_rdataset_next(rdataset);
                    273:                        }
                    274:                }
                    275:                result = dns_message_nextname(msg, section);
                    276:                if (result == ISC_R_NOMORE)
                    277:                        break;
                    278:                else if (result != ISC_R_SUCCESS) {
                    279:                        return (result);
                    280:                }
                    281:        }
                    282:        return (ISC_R_SUCCESS);
                    283: }
                    284:
                    285: static isc_result_t
                    286: detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
                    287:             dns_section_t section) {
                    288:        isc_result_t result, loopresult;
                    289:        dns_name_t *name;
                    290:        dns_rdataset_t *rdataset = NULL;
                    291:        dns_rdata_t rdata = DNS_RDATA_INIT;
                    292:        char namebuf[DNS_NAME_FORMATSIZE];
                    293:
                    294:        UNUSED(query);
                    295:
                    296:        debug("detailsection()");
                    297:
                    298:        if (headers) {
                    299:                switch (section) {
                    300:                case DNS_SECTION_QUESTION:
                    301:                        puts("    QUESTIONS:");
                    302:                        break;
                    303:                case DNS_SECTION_ANSWER:
                    304:                        puts("    ANSWERS:");
                    305:                        break;
                    306:                case DNS_SECTION_AUTHORITY:
                    307:                        puts("    AUTHORITY RECORDS:");
                    308:                        break;
                    309:                case DNS_SECTION_ADDITIONAL:
                    310:                        puts("    ADDITIONAL RECORDS:");
                    311:                        break;
                    312:                }
                    313:        }
                    314:
                    315:        result = dns_message_firstname(msg, section);
                    316:        if (result == ISC_R_NOMORE)
                    317:                return (ISC_R_SUCCESS);
                    318:        else if (result != ISC_R_SUCCESS)
                    319:                return (result);
                    320:        for (;;) {
                    321:                name = NULL;
                    322:                dns_message_currentname(msg, section,
                    323:                                        &name);
                    324:                for (rdataset = ISC_LIST_HEAD(name->list);
                    325:                     rdataset != NULL;
                    326:                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
                    327:                        if (section == DNS_SECTION_QUESTION) {
                    328:                                dns_name_format(name, namebuf,
                    329:                                                sizeof(namebuf));
                    330:                                printf("\t%s, ", namebuf);
                    331:                                dns_rdatatype_format(rdataset->type,
                    332:                                                     namebuf,
                    333:                                                     sizeof(namebuf));
                    334:                                printf("type = %s, ", namebuf);
                    335:                                dns_rdataclass_format(rdataset->rdclass,
                    336:                                                      namebuf,
                    337:                                                      sizeof(namebuf));
                    338:                                printf("class = %s\n", namebuf);
                    339:                        }
                    340:                        loopresult = dns_rdataset_first(rdataset);
                    341:                        while (loopresult == ISC_R_SUCCESS) {
                    342:                                dns_rdataset_current(rdataset, &rdata);
                    343:
                    344:                                dns_name_format(name, namebuf,
                    345:                                                sizeof(namebuf));
                    346:                                printf("    ->  %s\n", namebuf);
                    347:
                    348:                                switch (rdata.type) {
                    349:                                case dns_rdatatype_soa:
                    350:                                        printsoa(&rdata);
                    351:                                        break;
                    352:                                default:
                    353:                                        printf("\t");
                    354:                                        printrdata(&rdata);
                    355:                                }
                    356:                                dns_rdata_reset(&rdata);
                    357:                                printf("\tttl = %u\n", rdataset->ttl);
                    358:                                loopresult = dns_rdataset_next(rdataset);
                    359:                        }
                    360:                }
                    361:                result = dns_message_nextname(msg, section);
                    362:                if (result == ISC_R_NOMORE)
                    363:                        break;
                    364:                else if (result != ISC_R_SUCCESS) {
                    365:                        return (result);
                    366:                }
                    367:        }
                    368:        return (ISC_R_SUCCESS);
                    369: }
                    370:
                    371: static void
                    372: received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query)
                    373: {
                    374:        UNUSED(bytes);
                    375:        UNUSED(from);
                    376:        UNUSED(query);
                    377: }
                    378:
                    379: static void
                    380: trying(char *frm, dig_lookup_t *lookup) {
                    381:        UNUSED(frm);
                    382:        UNUSED(lookup);
                    383: }
                    384:
                    385: static isc_result_t
                    386: printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
                    387:        char servtext[ISC_SOCKADDR_FORMATSIZE];
                    388:
                    389:        /* I've we've gotten this far, we've reached a server. */
                    390:        query_error = 0;
                    391:
                    392:        debug("printmessage()");
                    393:
                    394:        isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
                    395:        printf("Server:\t\t%s\n", query->userarg);
                    396:        printf("Address:\t%s\n", servtext);
                    397:
                    398:        puts("");
                    399:
                    400:        if (!short_form) {
                    401:                puts("------------");
                    402:                /*              detailheader(query, msg);*/
                    403:                detailsection(query, msg, ISC_TRUE, DNS_SECTION_QUESTION);
                    404:                detailsection(query, msg, ISC_TRUE, DNS_SECTION_ANSWER);
                    405:                detailsection(query, msg, ISC_TRUE, DNS_SECTION_AUTHORITY);
                    406:                detailsection(query, msg, ISC_TRUE, DNS_SECTION_ADDITIONAL);
                    407:                puts("------------");
                    408:        }
                    409:
                    410:        if (msg->rcode != 0) {
                    411:                char nametext[DNS_NAME_FORMATSIZE];
                    412:                dns_name_format(query->lookup->name,
                    413:                                nametext, sizeof(nametext));
                    414:                printf("** server can't find %s: %s\n",
                    415:                       nametext, rcode_totext(msg->rcode));
                    416:                debug("returning with rcode == 0");
                    417:
                    418:                /* the lookup failed */
                    419:                print_error |= 1;
                    420:                return (ISC_R_SUCCESS);
                    421:        }
                    422:
                    423:        if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
                    424:                puts("Non-authoritative answer:");
                    425:        if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
                    426:                printsection(query, msg, headers, DNS_SECTION_ANSWER);
                    427:        else
                    428:                printf("*** Can't find %s: No answer\n",
                    429:                       query->lookup->textname);
                    430:
                    431:        if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
                    432:            (query->lookup->rdtype != dns_rdatatype_a)) {
                    433:                puts("\nAuthoritative answers can be found from:");
                    434:                printsection(query, msg, headers,
                    435:                             DNS_SECTION_AUTHORITY);
                    436:                printsection(query, msg, headers,
                    437:                             DNS_SECTION_ADDITIONAL);
                    438:        }
                    439:        return (ISC_R_SUCCESS);
                    440: }
                    441:
                    442: static void
                    443: show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
                    444:        dig_server_t *srv;
                    445:        isc_sockaddr_t sockaddr;
                    446:        dig_searchlist_t *listent;
                    447:        isc_result_t result;
                    448:
                    449:        srv = ISC_LIST_HEAD(server_list);
                    450:
                    451:        while (srv != NULL) {
                    452:                char sockstr[ISC_SOCKADDR_FORMATSIZE];
                    453:
                    454:                result = get_address(srv->servername, port, &sockaddr);
                    455:                check_result(result, "get_address");
                    456:
                    457:                isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
                    458:                printf("Default server: %s\nAddress: %s\n",
                    459:                        srv->userarg, sockstr);
                    460:                if (!full)
                    461:                        return;
                    462:                srv = ISC_LIST_NEXT(srv, link);
                    463:        }
                    464:        if (serv_only)
                    465:                return;
                    466:        printf("\nSet options:\n");
                    467:        printf("  %s\t\t\t%s\t\t%s\n",
                    468:               tcpmode ? "vc" : "novc",
                    469:               short_form ? "nodebug" : "debug",
                    470:               debugging ? "d2" : "nod2");
                    471:        printf("  %s\t\t%s\n",
                    472:               usesearch ? "search" : "nosearch",
                    473:               recurse ? "recurse" : "norecurse");
                    474:        printf("  timeout = %u\t\tretry = %d\tport = %u\tndots = %d\n",
                    475:               timeout, tries, port, ndots);
                    476:        printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
                    477:        printf("  srchlist = ");
                    478:        for (listent = ISC_LIST_HEAD(search_list);
                    479:             listent != NULL;
                    480:             listent = ISC_LIST_NEXT(listent, link)) {
                    481:                     printf("%s", listent->origin);
                    482:                     if (ISC_LIST_NEXT(listent, link) != NULL)
                    483:                             printf("/");
                    484:        }
                    485:        printf("\n");
                    486: }
                    487:
                    488: static isc_boolean_t
                    489: testtype(char *typetext) {
                    490:        isc_result_t result;
                    491:        isc_textregion_t tr;
                    492:        dns_rdatatype_t rdtype;
                    493:
                    494:        tr.base = typetext;
                    495:        tr.length = strlen(typetext);
                    496:        result = dns_rdatatype_fromtext(&rdtype, &tr);
                    497:        if (result == ISC_R_SUCCESS)
                    498:                return (ISC_TRUE);
                    499:        else {
                    500:                printf("unknown query type: %s\n", typetext);
                    501:                return (ISC_FALSE);
                    502:        }
                    503: }
                    504:
                    505: static isc_boolean_t
                    506: testclass(char *typetext) {
                    507:        isc_result_t result;
                    508:        isc_textregion_t tr;
                    509:        dns_rdataclass_t rdclass;
                    510:
                    511:        tr.base = typetext;
                    512:        tr.length = strlen(typetext);
                    513:        result = dns_rdataclass_fromtext(&rdclass, &tr);
                    514:        if (result == ISC_R_SUCCESS)
                    515:                return (ISC_TRUE);
                    516:        else {
                    517:                printf("unknown query class: %s\n", typetext);
                    518:                return (ISC_FALSE);
                    519:        }
                    520: }
                    521:
                    522: static void
                    523: set_port(const char *value) {
                    524:        uint32_t n;
                    525:        isc_result_t result = parse_uint(&n, value, 65535, "port");
                    526:        if (result == ISC_R_SUCCESS)
                    527:                port = (uint16_t) n;
                    528: }
                    529:
                    530: static void
                    531: set_timeout(const char *value) {
                    532:        uint32_t n;
                    533:        isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
                    534:        if (result == ISC_R_SUCCESS)
                    535:                timeout = n;
                    536: }
                    537:
                    538: static void
                    539: set_tries(const char *value) {
                    540:        uint32_t n;
                    541:        isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
                    542:        if (result == ISC_R_SUCCESS)
                    543:                tries = n;
                    544: }
                    545:
                    546: static void
                    547: set_ndots(const char *value) {
                    548:        uint32_t n;
                    549:        isc_result_t result = parse_uint(&n, value, 128, "ndots");
                    550:        if (result == ISC_R_SUCCESS)
                    551:                ndots = n;
                    552: }
                    553:
                    554: static void
                    555: version(void) {
                    556:        fputs("nslookup " VERSION "\n", stderr);
                    557: }
                    558:
                    559: static void
                    560: setoption(char *opt) {
                    561:        size_t l = strlen(opt);
                    562:
                    563: #define CHECKOPT(A, N) \
                    564:        ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0))
                    565:
                    566:        if (CHECKOPT("all", 3)) {
                    567:                show_settings(ISC_TRUE, ISC_FALSE);
                    568:        } else if (strncasecmp(opt, "class=", 6) == 0) {
                    569:                if (testclass(&opt[6]))
                    570:                        strlcpy(defclass, &opt[6], sizeof(defclass));
                    571:        } else if (strncasecmp(opt, "cl=", 3) == 0) {
                    572:                if (testclass(&opt[3]))
                    573:                        strlcpy(defclass, &opt[3], sizeof(defclass));
                    574:        } else if (strncasecmp(opt, "type=", 5) == 0) {
                    575:                if (testtype(&opt[5]))
                    576:                        strlcpy(deftype, &opt[5], sizeof(deftype));
                    577:        } else if (strncasecmp(opt, "ty=", 3) == 0) {
                    578:                if (testtype(&opt[3]))
                    579:                        strlcpy(deftype, &opt[3], sizeof(deftype));
                    580:        } else if (strncasecmp(opt, "querytype=", 10) == 0) {
                    581:                if (testtype(&opt[10]))
                    582:                        strlcpy(deftype, &opt[10], sizeof(deftype));
                    583:        } else if (strncasecmp(opt, "query=", 6) == 0) {
                    584:                if (testtype(&opt[6]))
                    585:                        strlcpy(deftype, &opt[6], sizeof(deftype));
                    586:        } else if (strncasecmp(opt, "qu=", 3) == 0) {
                    587:                if (testtype(&opt[3]))
                    588:                        strlcpy(deftype, &opt[3], sizeof(deftype));
                    589:        } else if (strncasecmp(opt, "q=", 2) == 0) {
                    590:                if (testtype(&opt[2]))
                    591:                        strlcpy(deftype, &opt[2], sizeof(deftype));
                    592:        } else if (strncasecmp(opt, "domain=", 7) == 0) {
                    593:                strlcpy(domainopt, &opt[7], sizeof(domainopt));
                    594:                set_search_domain(domainopt);
                    595:                usesearch = ISC_TRUE;
                    596:        } else if (strncasecmp(opt, "do=", 3) == 0) {
                    597:                strlcpy(domainopt, &opt[3], sizeof(domainopt));
                    598:                set_search_domain(domainopt);
                    599:                usesearch = ISC_TRUE;
                    600:        } else if (strncasecmp(opt, "port=", 5) == 0) {
                    601:                set_port(&opt[5]);
                    602:        } else if (strncasecmp(opt, "po=", 3) == 0) {
                    603:                set_port(&opt[3]);
                    604:        } else if (strncasecmp(opt, "timeout=", 8) == 0) {
                    605:                set_timeout(&opt[8]);
                    606:        } else if (strncasecmp(opt, "t=", 2) == 0) {
                    607:                set_timeout(&opt[2]);
                    608:        } else if (CHECKOPT("recurse", 3)) {
                    609:                recurse = ISC_TRUE;
                    610:        } else if (CHECKOPT("norecurse", 5)) {
                    611:                recurse = ISC_FALSE;
                    612:        } else if (strncasecmp(opt, "retry=", 6) == 0) {
                    613:                set_tries(&opt[6]);
                    614:        } else if (strncasecmp(opt, "ret=", 4) == 0) {
                    615:                set_tries(&opt[4]);
                    616:        } else if (CHECKOPT("defname", 3)) {
                    617:                usesearch = ISC_TRUE;
                    618:        } else if (CHECKOPT("nodefname", 5)) {
                    619:                usesearch = ISC_FALSE;
                    620:        } else if (CHECKOPT("vc", 2) == 0) {
                    621:                tcpmode = ISC_TRUE;
                    622:        } else if (CHECKOPT("novc", 4) == 0) {
                    623:                tcpmode = ISC_FALSE;
                    624:        } else if (CHECKOPT("debug", 3) == 0) {
                    625:                short_form = ISC_FALSE;
                    626:                showsearch = ISC_TRUE;
                    627:        } else if (CHECKOPT("nodebug", 5) == 0) {
                    628:                short_form = ISC_TRUE;
                    629:                showsearch = ISC_FALSE;
                    630:        } else if (CHECKOPT("d2", 2) == 0) {
                    631:                debugging = ISC_TRUE;
                    632:        } else if (CHECKOPT("nod2", 4) == 0) {
                    633:                debugging = ISC_FALSE;
                    634:        } else if (CHECKOPT("search", 3) == 0) {
                    635:                usesearch = ISC_TRUE;
                    636:        } else if (CHECKOPT("nosearch", 5) == 0) {
                    637:                usesearch = ISC_FALSE;
                    638:        } else if (CHECKOPT("sil", 3) == 0) {
                    639:                /* deprecation_msg = ISC_FALSE; */
                    640:        } else if (CHECKOPT("fail", 3) == 0) {
                    641:                nofail=ISC_FALSE;
                    642:        } else if (CHECKOPT("nofail", 5) == 0) {
                    643:                nofail=ISC_TRUE;
                    644:        } else if (strncasecmp(opt, "ndots=", 6) == 0) {
                    645:                set_ndots(&opt[6]);
                    646:        } else {
                    647:                printf("*** Invalid option: %s\n", opt);
                    648:        }
                    649: }
                    650:
                    651: static void
                    652: addlookup(char *opt) {
                    653:        dig_lookup_t *lookup;
                    654:        isc_result_t result;
                    655:        isc_textregion_t tr;
                    656:        dns_rdatatype_t rdtype;
                    657:        dns_rdataclass_t rdclass;
                    658:        char store[MXNAME];
                    659:
                    660:        debug("addlookup()");
                    661:        tr.base = deftype;
                    662:        tr.length = strlen(deftype);
                    663:        result = dns_rdatatype_fromtext(&rdtype, &tr);
                    664:        if (result != ISC_R_SUCCESS) {
                    665:                printf("unknown query type: %s\n", deftype);
                    666:                rdclass = dns_rdatatype_a;
                    667:        }
                    668:        tr.base = defclass;
                    669:        tr.length = strlen(defclass);
                    670:        result = dns_rdataclass_fromtext(&rdclass, &tr);
                    671:        if (result != ISC_R_SUCCESS) {
                    672:                printf("unknown query class: %s\n", defclass);
                    673:                rdclass = dns_rdataclass_in;
                    674:        }
                    675:        lookup = make_empty_lookup();
                    676:        if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
                    677:            == ISC_R_SUCCESS) {
                    678:                strlcpy(lookup->textname, store, sizeof(lookup->textname));
                    679:                lookup->rdtype = dns_rdatatype_ptr;
                    680:                lookup->rdtypeset = ISC_TRUE;
                    681:        } else {
                    682:                strlcpy(lookup->textname, opt, sizeof(lookup->textname));
                    683:                lookup->rdtype = rdtype;
                    684:                lookup->rdtypeset = ISC_TRUE;
                    685:        }
                    686:        lookup->rdclass = rdclass;
                    687:        lookup->rdclassset = ISC_TRUE;
                    688:        lookup->trace = ISC_FALSE;
                    689:        lookup->trace_root = lookup->trace;
                    690:        lookup->ns_search_only = ISC_FALSE;
                    691:        lookup->identify = identify;
                    692:        lookup->recurse = recurse;
                    693:        lookup->aaonly = aaonly;
                    694:        lookup->retries = tries;
                    695:        lookup->udpsize = 0;
                    696:        lookup->comments = comments;
                    697:        lookup->tcp_mode = tcpmode;
                    698:        lookup->stats = stats;
                    699:        lookup->section_question = section_question;
                    700:        lookup->section_answer = section_answer;
                    701:        lookup->section_authority = section_authority;
                    702:        lookup->section_additional = section_additional;
                    703:        lookup->new_search = ISC_TRUE;
                    704:        if (nofail)
                    705:                lookup->servfail_stops = ISC_FALSE;
                    706:        ISC_LIST_INIT(lookup->q);
                    707:        ISC_LINK_INIT(lookup, link);
                    708:        ISC_LIST_APPEND(lookup_list, lookup, link);
                    709:        lookup->origin = NULL;
                    710:        ISC_LIST_INIT(lookup->my_server_list);
                    711:        debug("looking up %s", lookup->textname);
                    712: }
                    713:
                    714: static void
                    715: do_next_command(char *input) {
                    716:        char *ptr, *arg;
                    717:
                    718:        ptr = next_token(&input, " \t\r\n");
                    719:        if (ptr == NULL)
                    720:                return;
                    721:        arg = next_token(&input, " \t\r\n");
1.10    ! deraadt   722:        if (strcasecmp(ptr, "set") == 0) {
        !           723:                if (arg == NULL)
        !           724:                        printf("Usage: set keyword=value, or set all\n");
        !           725:                else
        !           726:                        setoption(arg);
        !           727:        } else if ((strcasecmp(ptr, "server") == 0) ||
1.1       florian   728:                 (strcasecmp(ptr, "lserver") == 0)) {
1.9       deraadt   729:                isc_result_t res;
                    730:
                    731:                if (arg == NULL)
                    732:                        printf("usage: server hostname\n");
                    733:                else if ((res = set_nameserver(arg))) {
                    734:                        printf("couldn't get address for '%s': %s\n",
                    735:                            arg, isc_result_totext(res));
                    736:                } else {
                    737:                        check_ra = ISC_FALSE;
                    738:                        show_settings(ISC_TRUE, ISC_TRUE);
                    739:                }
1.1       florian   740:        } else if (strcasecmp(ptr, "exit") == 0) {
                    741:                in_use = ISC_FALSE;
                    742:        } else if (strcasecmp(ptr, "help") == 0 ||
                    743:                   strcasecmp(ptr, "?") == 0) {
                    744:                printf("The '%s' command is not yet implemented.\n", ptr);
                    745:        } else if (strcasecmp(ptr, "finger") == 0 ||
                    746:                   strcasecmp(ptr, "root") == 0 ||
                    747:                   strcasecmp(ptr, "ls") == 0 ||
                    748:                   strcasecmp(ptr, "view") == 0) {
                    749:                printf("The '%s' command is not implemented.\n", ptr);
                    750:        } else
                    751:                addlookup(ptr);
                    752: }
                    753:
                    754: static void
                    755: get_next_command(void) {
                    756:        char *buf;
                    757:        char *ptr;
                    758:
                    759:        fflush(stdout);
                    760:        buf = malloc(COMMSIZE);
                    761:        if (buf == NULL)
                    762:                fatal("memory allocation failure");
                    763:        if (interactive) {
                    764:                fputs("> ", stderr);
                    765:                fflush(stderr);
                    766:                ptr = fgets(buf, COMMSIZE, stdin);
                    767:        } else
                    768:                ptr = fgets(buf, COMMSIZE, stdin);
                    769:        if (ptr == NULL) {
                    770:                in_use = ISC_FALSE;
                    771:        } else
                    772:                do_next_command(ptr);
                    773:        free(buf);
                    774: }
                    775:
                    776: static void
                    777: parse_args(int argc, char **argv) {
                    778:        isc_boolean_t have_lookup = ISC_FALSE;
                    779:
                    780:        usesearch = ISC_TRUE;
                    781:        for (argc--, argv++; argc > 0; argc--, argv++) {
                    782:                debug("main parsing %s", argv[0]);
                    783:                if (argv[0][0] == '-') {
                    784:                        if (strncasecmp(argv[0], "-ver", 4) == 0) {
                    785:                                version();
                    786:                                exit(0);
                    787:                        } else if (argv[0][1] != 0) {
                    788:                                setoption(&argv[0][1]);
                    789:                        } else
                    790:                                have_lookup = ISC_TRUE;
                    791:                } else {
                    792:                        if (!have_lookup) {
                    793:                                have_lookup = ISC_TRUE;
                    794:                                in_use = ISC_TRUE;
                    795:                                addlookup(argv[0]);
                    796:                        } else {
1.9       deraadt   797:                                isc_result_t res;
                    798:
                    799:                                if ((res = set_nameserver(argv[0])))
                    800:                                        fatal("couldn't get address for '%s': %s",
                    801:                                            argv[0], isc_result_totext(res));
1.1       florian   802:                                check_ra = ISC_FALSE;
                    803:                        }
                    804:                }
                    805:        }
                    806: }
                    807:
                    808: static void
                    809: flush_lookup_list(void) {
                    810:        dig_lookup_t *l, *lp;
                    811:        dig_query_t *q, *qp;
                    812:        dig_server_t *s, *sp;
                    813:
                    814:        lookup_counter = 0;
                    815:        l = ISC_LIST_HEAD(lookup_list);
                    816:        while (l != NULL) {
                    817:                q = ISC_LIST_HEAD(l->q);
                    818:                while (q != NULL) {
                    819:                        if (q->sock != NULL) {
                    820:                                isc_socket_cancel(q->sock, NULL,
                    821:                                                  ISC_SOCKCANCEL_ALL);
                    822:                                isc_socket_detach(&q->sock);
                    823:                        }
                    824:                        if (ISC_LINK_LINKED(&q->recvbuf, link))
                    825:                                ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
                    826:                                                 link);
                    827:                        if (ISC_LINK_LINKED(&q->lengthbuf, link))
                    828:                                ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
                    829:                                                 link);
                    830:                        isc_buffer_invalidate(&q->recvbuf);
                    831:                        isc_buffer_invalidate(&q->lengthbuf);
                    832:                        qp = q;
                    833:                        q = ISC_LIST_NEXT(q, link);
                    834:                        ISC_LIST_DEQUEUE(l->q, qp, link);
                    835:                        free(qp);
                    836:                }
                    837:                s = ISC_LIST_HEAD(l->my_server_list);
                    838:                while (s != NULL) {
                    839:                        sp = s;
                    840:                        s = ISC_LIST_NEXT(s, link);
                    841:                        ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
                    842:                        free(sp);
                    843:
                    844:                }
                    845:                if (l->sendmsg != NULL)
                    846:                        dns_message_destroy(&l->sendmsg);
                    847:                lp = l;
                    848:                l = ISC_LIST_NEXT(l, link);
                    849:                ISC_LIST_DEQUEUE(lookup_list, lp, link);
                    850:                free(lp);
                    851:        }
                    852: }
                    853:
                    854: static void
                    855: getinput(isc_task_t *task, isc_event_t *event) {
                    856:        UNUSED(task);
                    857:        if (global_event == NULL)
                    858:                global_event = event;
                    859:        while (in_use) {
                    860:                get_next_command();
                    861:                if (ISC_LIST_HEAD(lookup_list) != NULL) {
                    862:                        start_lookup();
                    863:                        return;
                    864:                }
                    865:        }
                    866:        isc_app_shutdown();
                    867: }
                    868:
                    869: int
                    870: nslookup_main(int argc, char **argv) {
                    871:        isc_result_t result;
                    872:
                    873:        interactive = ISC_TF(isatty(0));
                    874:
                    875:        ISC_LIST_INIT(lookup_list);
                    876:        ISC_LIST_INIT(server_list);
1.3       florian   877:        ISC_LIST_INIT(root_hints_server_list);
1.1       florian   878:        ISC_LIST_INIT(search_list);
                    879:
                    880:        check_ra = ISC_TRUE;
                    881:
                    882:        /* setup dighost callbacks */
                    883:        dighost_printmessage = printmessage;
                    884:        dighost_received = received;
                    885:        dighost_trying = trying;
                    886:        dighost_shutdown = query_finished;
                    887:
                    888:        result = isc_app_start();
                    889:        check_result(result, "isc_app_start");
                    890:
                    891:        if (pledge("stdio rpath inet dns", NULL) == -1) {
                    892:                perror("pledge");
                    893:                exit(1);
                    894:        }
                    895:
                    896:        setup_libs();
                    897:        progname = argv[0];
                    898:
                    899:        if (pledge("stdio inet dns", NULL) == -1) {
                    900:                perror("pledge");
                    901:                exit(1);
                    902:        }
                    903:
                    904:        parse_args(argc, argv);
                    905:
                    906:        setup_system(ISC_FALSE, ISC_FALSE);
                    907:        if (domainopt[0] != '\0')
                    908:                set_search_domain(domainopt);
                    909:        if (in_use)
                    910:                result = isc_app_onrun(global_task, onrun_callback,
                    911:                                       NULL);
                    912:        else
                    913:                result = isc_app_onrun(global_task, getinput, NULL);
                    914:        check_result(result, "isc_app_onrun");
                    915:        in_use = ISC_TF(!in_use);
                    916:
                    917:        (void)isc_app_run();
                    918:
                    919:        puts("");
                    920:        debug("done, and starting to shut down");
                    921:        if (global_event != NULL)
                    922:                isc_event_free(&global_event);
                    923:        cancel_all();
                    924:        destroy_libs();
                    925:
                    926:        return (query_error | print_error);
                    927: }