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

Annotation of src/usr.bin/dig/host.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: /*! \file */
                     18: #include <sys/cdefs.h>
                     19:
                     20: #include <err.h>
                     21: #include <limits.h>
                     22: #include <locale.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
1.10    ! jsg        26: #include <time.h>
        !            27: #include <stdint.h>
1.1       florian    28:
                     29: #include <isc/app.h>
                     30: #include <isc/util.h>
1.10    ! jsg        31: #include <isc/time.h>
1.1       florian    32:
                     33: #include <dns/fixedname.h>
                     34: #include <dns/message.h>
                     35: #include <dns/name.h>
                     36: #include <dns/rdata.h>
                     37: #include <dns/rdataclass.h>
                     38: #include <dns/rdataset.h>
                     39: #include <dns/rdatatype.h>
                     40: #include "rdatastruct.h"
                     41:
                     42: #include "dig.h"
                     43:
                     44: static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
                     45: static isc_boolean_t default_lookups = ISC_TRUE;
                     46: static int seen_error = -1;
                     47: static isc_boolean_t list_addresses = ISC_TRUE;
                     48: static dns_rdatatype_t list_type = dns_rdatatype_a;
                     49: static isc_boolean_t printed_server = ISC_FALSE;
                     50: static isc_boolean_t ipv4only = ISC_FALSE, ipv6only = ISC_FALSE;
                     51:
                     52: static const char *opcodetext[] = {
                     53:        "QUERY",
                     54:        "IQUERY",
                     55:        "STATUS",
                     56:        "RESERVED3",
                     57:        "NOTIFY",
                     58:        "UPDATE",
                     59:        "RESERVED6",
                     60:        "RESERVED7",
                     61:        "RESERVED8",
                     62:        "RESERVED9",
                     63:        "RESERVED10",
                     64:        "RESERVED11",
                     65:        "RESERVED12",
                     66:        "RESERVED13",
                     67:        "RESERVED14",
                     68:        "RESERVED15"
                     69: };
                     70:
                     71: static const char *rcodetext[] = {
                     72:        "NOERROR",
                     73:        "FORMERR",
                     74:        "SERVFAIL",
                     75:        "NXDOMAIN",
                     76:        "NOTIMP",
                     77:        "REFUSED",
                     78:        "YXDOMAIN",
                     79:        "YXRRSET",
                     80:        "NXRRSET",
                     81:        "NOTAUTH",
                     82:        "NOTZONE",
                     83:        "RESERVED11",
                     84:        "RESERVED12",
                     85:        "RESERVED13",
                     86:        "RESERVED14",
                     87:        "RESERVED15",
                     88:        "BADVERS"
                     89: };
                     90:
                     91: struct rtype {
                     92:        unsigned int type;
                     93:        const char *text;
                     94: };
                     95:
                     96: static struct rtype rtypes[] = {
                     97:        { 1,    "has address" },
                     98:        { 2,    "name server" },
                     99:        { 5,    "is an alias for" },
                    100:        { 11,   "has well known services" },
                    101:        { 12,   "domain name pointer" },
                    102:        { 13,   "host information" },
                    103:        { 15,   "mail is handled by" },
                    104:        { 16,   "descriptive text" },
                    105:        { 19,   "x25 address" },
                    106:        { 20,   "ISDN address" },
                    107:        { 24,   "has signature" },
                    108:        { 25,   "has key" },
                    109:        { 28,   "has IPv6 address" },
                    110:        { 29,   "location" },
                    111:        { 0, NULL }
                    112: };
                    113:
                    114: static char *
                    115: rcode_totext(dns_rcode_t rcode)
                    116: {
                    117:        static char buf[sizeof("?65535")];
                    118:        union {
                    119:                const char *consttext;
                    120:                char *deconsttext;
                    121:        } totext;
                    122:
                    123:        if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
                    124:                snprintf(buf, sizeof(buf), "?%u", rcode);
                    125:                totext.deconsttext = buf;
                    126:        } else
                    127:                totext.consttext = rcodetext[rcode];
                    128:        return totext.deconsttext;
                    129: }
                    130:
                    131: static __dead void
                    132: show_usage(void);
                    133:
                    134: static void
                    135: show_usage(void) {
                    136:        fputs(
                    137: "usage: host [-46aCdilrsTVvw] [-c class] [-m flag] [-N ndots] [-R number]\n"
                    138: "            [-t type] [-W wait] name [server]\n", stderr);
                    139:        exit(1);
                    140: }
                    141:
                    142: static void
                    143: host_shutdown(void) {
                    144:        (void) isc_app_shutdown();
                    145: }
                    146:
                    147: static void
                    148: received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
1.6       florian   149:        struct timespec now;
1.1       florian   150:        int diff;
                    151:
                    152:        if (!short_form) {
                    153:                char fromtext[ISC_SOCKADDR_FORMATSIZE];
                    154:                isc_sockaddr_format(from, fromtext, sizeof(fromtext));
1.9       florian   155:                clock_gettime(CLOCK_MONOTONIC, &now);
1.1       florian   156:                diff = (int) isc_time_microdiff(&now, &query->time_sent);
                    157:                printf("Received %u bytes from %s in %d ms\n",
                    158:                       bytes, fromtext, diff/1000);
                    159:        }
                    160: }
                    161:
                    162: static void
                    163: trying(char *frm, dig_lookup_t *lookup) {
                    164:        UNUSED(lookup);
                    165:
                    166:        if (!short_form)
                    167:                printf("Trying \"%s\"\n", frm);
                    168: }
                    169:
                    170: static void
                    171: say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
                    172:            dig_query_t *query)
                    173: {
                    174:        isc_buffer_t *b = NULL;
                    175:        char namestr[DNS_NAME_FORMATSIZE];
                    176:        isc_region_t r;
                    177:        isc_result_t result;
                    178:        unsigned int bufsize = BUFSIZ;
                    179:
                    180:        dns_name_format(name, namestr, sizeof(namestr));
                    181:  retry:
                    182:        result = isc_buffer_allocate(&b, bufsize);
                    183:        check_result(result, "isc_buffer_allocate");
                    184:        result = dns_rdata_totext(rdata, NULL, b);
                    185:        if (result == ISC_R_NOSPACE) {
                    186:                isc_buffer_free(&b);
                    187:                bufsize *= 2;
                    188:                goto retry;
                    189:        }
                    190:        check_result(result, "dns_rdata_totext");
                    191:        isc_buffer_usedregion(b, &r);
                    192:        if (query->lookup->identify_previous_line) {
                    193:                printf("Nameserver %s:\n\t",
                    194:                        query->servname);
                    195:        }
                    196:        printf("%s %s %.*s", namestr,
                    197:               msg, (int)r.length, (char *)r.base);
                    198:        if (query->lookup->identify) {
                    199:                printf(" on server %s", query->servname);
                    200:        }
                    201:        printf("\n");
                    202:        isc_buffer_free(&b);
                    203: }
                    204: static isc_result_t
                    205: printsection(dns_message_t *msg, dns_section_t sectionid,
                    206:             const char *section_name, isc_boolean_t headers,
                    207:             dig_query_t *query)
                    208: {
                    209:        dns_name_t *name, *print_name;
                    210:        dns_rdataset_t *rdataset;
                    211:        dns_rdata_t rdata = DNS_RDATA_INIT;
                    212:        isc_buffer_t target;
                    213:        isc_result_t result, loopresult;
                    214:        isc_region_t r;
                    215:        dns_name_t empty_name;
                    216:        char tbuf[4096];
                    217:        isc_boolean_t first;
                    218:        isc_boolean_t no_rdata;
                    219:
                    220:        if (sectionid == DNS_SECTION_QUESTION)
                    221:                no_rdata = ISC_TRUE;
                    222:        else
                    223:                no_rdata = ISC_FALSE;
                    224:
                    225:        if (headers)
                    226:                printf(";; %s SECTION:\n", section_name);
                    227:
                    228:        dns_name_init(&empty_name, NULL);
                    229:
                    230:        result = dns_message_firstname(msg, sectionid);
                    231:        if (result == ISC_R_NOMORE)
                    232:                return (ISC_R_SUCCESS);
                    233:        else if (result != ISC_R_SUCCESS)
                    234:                return (result);
                    235:
                    236:        for (;;) {
                    237:                name = NULL;
                    238:                dns_message_currentname(msg, sectionid, &name);
                    239:
                    240:                isc_buffer_init(&target, tbuf, sizeof(tbuf));
                    241:                first = ISC_TRUE;
                    242:                print_name = name;
                    243:
                    244:                for (rdataset = ISC_LIST_HEAD(name->list);
                    245:                     rdataset != NULL;
                    246:                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
                    247:                        if (query->lookup->rdtype == dns_rdatatype_axfr &&
                    248:                            !((!list_addresses &&
                    249:                               (list_type == dns_rdatatype_any ||
                    250:                                rdataset->type == list_type)) ||
                    251:                              (list_addresses &&
                    252:                               (rdataset->type == dns_rdatatype_a ||
                    253:                                rdataset->type == dns_rdatatype_aaaa ||
                    254:                                rdataset->type == dns_rdatatype_ns ||
                    255:                                rdataset->type == dns_rdatatype_ptr))))
                    256:                                continue;
                    257:                        if (!short_form) {
                    258:                                result = dns_rdataset_totext(rdataset,
                    259:                                                             print_name,
                    260:                                                             ISC_FALSE,
                    261:                                                             no_rdata,
                    262:                                                             &target);
                    263:                                if (result != ISC_R_SUCCESS)
                    264:                                        return (result);
                    265:                                UNUSED(first); /* Shut up compiler. */
                    266:                        } else {
                    267:                                loopresult = dns_rdataset_first(rdataset);
                    268:                                while (loopresult == ISC_R_SUCCESS) {
                    269:                                        struct rtype *t;
                    270:                                        const char *rtt;
                    271:                                        char typebuf[DNS_RDATATYPE_FORMATSIZE];
                    272:                                        char typebuf2[DNS_RDATATYPE_FORMATSIZE
                    273:                                                     + 20];
                    274:                                        dns_rdataset_current(rdataset, &rdata);
                    275:
                    276:                                        for (t = rtypes; t->text != NULL; t++) {
                    277:                                                if (t->type == rdata.type) {
                    278:                                                        rtt = t->text;
                    279:                                                        goto found;
                    280:                                                }
                    281:                                        }
                    282:
                    283:                                        dns_rdatatype_format(rdata.type,
                    284:                                                             typebuf,
                    285:                                                             sizeof(typebuf));
                    286:                                        snprintf(typebuf2, sizeof(typebuf2),
                    287:                                                 "has %s record", typebuf);
                    288:                                        rtt = typebuf2;
                    289:                                found:
                    290:                                        say_message(print_name, rtt,
                    291:                                                    &rdata, query);
                    292:                                        dns_rdata_reset(&rdata);
                    293:                                        loopresult =
                    294:                                                dns_rdataset_next(rdataset);
                    295:                                }
                    296:                        }
                    297:                }
                    298:                if (!short_form) {
                    299:                        isc_buffer_usedregion(&target, &r);
                    300:                        if (no_rdata)
                    301:                                printf(";%.*s", (int)r.length,
                    302:                                       (char *)r.base);
                    303:                        else
                    304:                                printf("%.*s", (int)r.length, (char *)r.base);
                    305:                }
                    306:
                    307:                result = dns_message_nextname(msg, sectionid);
                    308:                if (result == ISC_R_NOMORE)
                    309:                        break;
                    310:                else if (result != ISC_R_SUCCESS)
                    311:                        return (result);
                    312:        }
                    313:
                    314:        return (ISC_R_SUCCESS);
                    315: }
                    316:
                    317: static isc_result_t
                    318: printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
                    319:           const char *set_name, isc_boolean_t headers)
                    320: {
                    321:        isc_buffer_t target;
                    322:        isc_result_t result;
                    323:        isc_region_t r;
                    324:        char tbuf[4096];
                    325:
                    326:        UNUSED(msg);
                    327:        if (headers)
                    328:                printf(";; %s SECTION:\n", set_name);
                    329:
                    330:        isc_buffer_init(&target, tbuf, sizeof(tbuf));
                    331:
                    332:        result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
                    333:                                     &target);
                    334:        if (result != ISC_R_SUCCESS)
                    335:                return (result);
                    336:        isc_buffer_usedregion(&target, &r);
                    337:        printf("%.*s", (int)r.length, (char *)r.base);
                    338:
                    339:        return (ISC_R_SUCCESS);
                    340: }
                    341:
                    342: static void
                    343: chase_cnamechain(dns_message_t *msg, dns_name_t *qname) {
                    344:        isc_result_t result;
                    345:        dns_rdataset_t *rdataset;
                    346:        dns_rdata_cname_t cname;
                    347:        dns_rdata_t rdata = DNS_RDATA_INIT;
                    348:        unsigned int i = msg->counts[DNS_SECTION_ANSWER];
                    349:
                    350:        while (i-- > 0) {
                    351:                rdataset = NULL;
                    352:                result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
                    353:                                              dns_rdatatype_cname, 0, NULL,
                    354:                                              &rdataset);
                    355:                if (result != ISC_R_SUCCESS)
                    356:                        return;
                    357:                result = dns_rdataset_first(rdataset);
                    358:                check_result(result, "dns_rdataset_first");
                    359:                dns_rdata_reset(&rdata);
                    360:                dns_rdataset_current(rdataset, &rdata);
                    361:                result = dns_rdata_tostruct(&rdata, &cname);
                    362:                check_result(result, "dns_rdata_tostruct");
                    363:                dns_name_copy(&cname.cname, qname, NULL);
                    364:                dns_rdata_freestruct(&cname);
                    365:        }
                    366: }
                    367:
                    368: static isc_result_t
                    369: printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
                    370:        isc_boolean_t did_flag = ISC_FALSE;
                    371:        dns_rdataset_t *opt, *tsig = NULL;
                    372:        dns_name_t *tsigname;
                    373:        isc_result_t result = ISC_R_SUCCESS;
                    374:        int force_error;
                    375:
                    376:        UNUSED(headers);
                    377:
                    378:        /*
                    379:         * We get called multiple times.
                    380:         * Preserve any existing error status.
                    381:         */
                    382:        force_error = (seen_error == 1) ? 1 : 0;
                    383:        seen_error = 1;
                    384:        if (listed_server && !printed_server) {
                    385:                char sockstr[ISC_SOCKADDR_FORMATSIZE];
                    386:
                    387:                printf("Using domain server:\n");
                    388:                printf("Name: %s\n", query->userarg);
                    389:                isc_sockaddr_format(&query->sockaddr, sockstr,
                    390:                                    sizeof(sockstr));
                    391:                printf("Address: %s\n", sockstr);
                    392:                printf("Aliases: \n\n");
                    393:                printed_server = ISC_TRUE;
                    394:        }
                    395:
                    396:        if (msg->rcode != 0) {
                    397:                char namestr[DNS_NAME_FORMATSIZE];
                    398:                dns_name_format(query->lookup->name, namestr, sizeof(namestr));
                    399:
                    400:                if (query->lookup->identify_previous_line)
                    401:                        printf("Nameserver %s:\n\t%s not found: %d(%s)\n",
                    402:                               query->servname,
                    403:                               (msg->rcode != dns_rcode_nxdomain) ? namestr :
                    404:                               query->lookup->textname, msg->rcode,
                    405:                               rcode_totext(msg->rcode));
                    406:                else
                    407:                        printf("Host %s not found: %d(%s)\n",
                    408:                               (msg->rcode != dns_rcode_nxdomain) ? namestr :
                    409:                               query->lookup->textname, msg->rcode,
                    410:                               rcode_totext(msg->rcode));
                    411:                return (ISC_R_SUCCESS);
                    412:        }
                    413:
                    414:        if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
                    415:                char namestr[DNS_NAME_FORMATSIZE];
                    416:                dig_lookup_t *lookup;
                    417:                dns_fixedname_t fixed;
                    418:                dns_name_t *name;
                    419:
                    420:                /* Add AAAA and MX lookups. */
                    421:                dns_fixedname_init(&fixed);
                    422:                name = dns_fixedname_name(&fixed);
                    423:                dns_name_copy(query->lookup->name, name, NULL);
                    424:                chase_cnamechain(msg, name);
                    425:                dns_name_format(name, namestr, sizeof(namestr));
                    426:                lookup = clone_lookup(query->lookup, ISC_FALSE);
                    427:                if (lookup != NULL) {
                    428:                        strlcpy(lookup->textname, namestr,
                    429:                                sizeof(lookup->textname));
                    430:                        lookup->rdtype = dns_rdatatype_aaaa;
                    431:                        lookup->rdtypeset = ISC_TRUE;
                    432:                        lookup->origin = NULL;
                    433:                        lookup->retries = tries;
                    434:                        ISC_LIST_APPEND(lookup_list, lookup, link);
                    435:                }
                    436:                lookup = clone_lookup(query->lookup, ISC_FALSE);
                    437:                if (lookup != NULL) {
                    438:                        strlcpy(lookup->textname, namestr,
                    439:                                sizeof(lookup->textname));
                    440:                        lookup->rdtype = dns_rdatatype_mx;
                    441:                        lookup->rdtypeset = ISC_TRUE;
                    442:                        lookup->origin = NULL;
                    443:                        lookup->retries = tries;
                    444:                        ISC_LIST_APPEND(lookup_list, lookup, link);
                    445:                }
                    446:        }
                    447:
                    448:        if (!short_form) {
                    449:                printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
                    450:                       opcodetext[msg->opcode], rcode_totext(msg->rcode),
                    451:                       msg->id);
                    452:                printf(";; flags: ");
                    453:                if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
                    454:                        printf("qr");
                    455:                        did_flag = ISC_TRUE;
                    456:                }
                    457:                if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
                    458:                        printf("%saa", did_flag ? " " : "");
                    459:                        did_flag = ISC_TRUE;
                    460:                }
                    461:                if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
                    462:                        printf("%stc", did_flag ? " " : "");
                    463:                        did_flag = ISC_TRUE;
                    464:                }
                    465:                if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
                    466:                        printf("%srd", did_flag ? " " : "");
                    467:                        did_flag = ISC_TRUE;
                    468:                }
                    469:                if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
                    470:                        printf("%sra", did_flag ? " " : "");
                    471:                        did_flag = ISC_TRUE;
                    472:                }
                    473:                if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
                    474:                        printf("%sad", did_flag ? " " : "");
                    475:                        did_flag = ISC_TRUE;
                    476:                }
                    477:                if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
                    478:                        printf("%scd", did_flag ? " " : "");
                    479:                        did_flag = ISC_TRUE;
                    480:                        POST(did_flag);
                    481:                }
                    482:                printf("; QUERY: %u, ANSWER: %u, "
                    483:                       "AUTHORITY: %u, ADDITIONAL: %u\n",
                    484:                       msg->counts[DNS_SECTION_QUESTION],
                    485:                       msg->counts[DNS_SECTION_ANSWER],
                    486:                       msg->counts[DNS_SECTION_AUTHORITY],
                    487:                       msg->counts[DNS_SECTION_ADDITIONAL]);
                    488:                opt = dns_message_getopt(msg);
                    489:                if (opt != NULL)
                    490:                        printf(";; EDNS: version: %u, udp=%u\n",
                    491:                               (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
                    492:                               (unsigned int)opt->rdclass);
                    493:                tsigname = NULL;
                    494:                tsig = dns_message_gettsig(msg, &tsigname);
                    495:                if (tsig != NULL)
                    496:                        printf(";; PSEUDOSECTIONS: TSIG\n");
                    497:        }
                    498:        if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
                    499:            !short_form) {
                    500:                printf("\n");
                    501:                result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
                    502:                                      ISC_TRUE, query);
                    503:                if (result != ISC_R_SUCCESS)
                    504:                        return (result);
                    505:        }
                    506:        if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
                    507:                if (!short_form)
                    508:                        printf("\n");
                    509:                result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
                    510:                                      ISC_TF(!short_form), query);
                    511:                if (result != ISC_R_SUCCESS)
                    512:                        return (result);
                    513:        }
                    514:
                    515:        if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
                    516:            !short_form) {
                    517:                printf("\n");
                    518:                result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
                    519:                                      ISC_TRUE, query);
                    520:                if (result != ISC_R_SUCCESS)
                    521:                        return (result);
                    522:        }
                    523:        if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
                    524:            !short_form) {
                    525:                printf("\n");
                    526:                result = printsection(msg, DNS_SECTION_ADDITIONAL,
                    527:                                      "ADDITIONAL", ISC_TRUE, query);
                    528:                if (result != ISC_R_SUCCESS)
                    529:                        return (result);
                    530:        }
                    531:        if ((tsig != NULL) && !short_form) {
                    532:                printf("\n");
                    533:                result = printrdata(msg, tsig, tsigname,
                    534:                                    "PSEUDOSECTION TSIG", ISC_TRUE);
                    535:                if (result != ISC_R_SUCCESS)
                    536:                        return (result);
                    537:        }
                    538:        if (!short_form)
                    539:                printf("\n");
                    540:
                    541:        if (short_form && !default_lookups &&
                    542:            ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
                    543:                char namestr[DNS_NAME_FORMATSIZE];
                    544:                char typestr[DNS_RDATATYPE_FORMATSIZE];
                    545:                dns_name_format(query->lookup->name, namestr, sizeof(namestr));
                    546:                dns_rdatatype_format(query->lookup->rdtype, typestr,
                    547:                                     sizeof(typestr));
                    548:                printf("%s has no %s record\n", namestr, typestr);
                    549:        }
                    550:        seen_error = force_error;
                    551:        return (result);
                    552: }
                    553:
                    554: static const char * optstring = "46ac:dilnrst:vVwCDN:R:TW:";
                    555:
                    556: /*% version */
                    557: static void
                    558: version(void) {
                    559:        fputs("host " VERSION "\n", stderr);
                    560: }
                    561:
                    562: static void
                    563: pre_parse_args(int argc, char **argv) {
                    564:        int c;
                    565:
                    566:        while ((c = getopt(argc, argv, optstring)) != -1) {
                    567:                switch (c) {
                    568:                case '4':
                    569:                        if (ipv6only)
                    570:                                fatal("only one of -4 and -6 allowed");
                    571:                        ipv4only = ISC_TRUE;
                    572:                        break;
                    573:                case '6':
                    574:                        if (ipv4only)
                    575:                                fatal("only one of -4 and -6 allowed");
                    576:                        ipv6only = ISC_TRUE;
                    577:                        break;
                    578:                case 'a': break;
                    579:                case 'c': break;
                    580:                case 'd': break;
                    581:                case 'i': break;
                    582:                case 'l': break;
                    583:                case 'n': break;
                    584:                case 'r': break;
                    585:                case 's': break;
                    586:                case 't': break;
                    587:                case 'v': break;
                    588:                case 'V':
                    589:                          version();
                    590:                          exit(0);
                    591:                          break;
                    592:                case 'w': break;
                    593:                case 'C': break;
                    594:                case 'D':
                    595:                        if (debugging)
                    596:                                debugtiming = ISC_TRUE;
                    597:                        debugging = ISC_TRUE;
                    598:                        break;
                    599:                case 'N': break;
                    600:                case 'R': break;
                    601:                case 'T': break;
                    602:                case 'W': break;
                    603:                default:
                    604:                        show_usage();
                    605:                }
                    606:        }
                    607:        optind = 1;
                    608:        optreset = 1;
                    609: }
                    610:
                    611: static void
                    612: parse_args(int argc, char **argv) {
                    613:        char hostname[MXNAME];
                    614:        dig_lookup_t *lookup;
                    615:        int c;
                    616:        char store[MXNAME];
                    617:        isc_textregion_t tr;
                    618:        isc_result_t result = ISC_R_SUCCESS;
                    619:        dns_rdatatype_t rdtype;
                    620:        dns_rdataclass_t rdclass;
                    621:        uint32_t serial = 0;
                    622:        const char *errstr;
                    623:
                    624:        lookup = make_empty_lookup();
                    625:
                    626:        lookup->servfail_stops = ISC_FALSE;
                    627:        lookup->comments = ISC_FALSE;
                    628:
                    629:        while ((c = getopt(argc, argv, optstring)) != -1) {
                    630:                switch (c) {
                    631:                case 'l':
                    632:                        lookup->tcp_mode = ISC_TRUE;
                    633:                        lookup->rdtype = dns_rdatatype_axfr;
                    634:                        lookup->rdtypeset = ISC_TRUE;
                    635:                        fatalexit = 3;
                    636:                        break;
                    637:                case 'v':
                    638:                case 'd':
                    639:                        short_form = ISC_FALSE;
                    640:                        break;
                    641:                case 'r':
                    642:                        lookup->recurse = ISC_FALSE;
                    643:                        break;
                    644:                case 't':
                    645:                        if (strncasecmp(optarg, "ixfr=", 5) == 0) {
                    646:                                rdtype = dns_rdatatype_ixfr;
                    647:                                /* XXXMPA add error checking */
                    648:                                serial = strtoul(optarg + 5,
                    649:                                                 NULL, 10);
                    650:                                result = ISC_R_SUCCESS;
                    651:                        } else {
                    652:                                tr.base = optarg;
                    653:                                tr.length = strlen(optarg);
                    654:                                result = dns_rdatatype_fromtext(&rdtype,
                    655:                                                   (isc_textregion_t *)&tr);
                    656:                        }
                    657:
                    658:                        if (result != ISC_R_SUCCESS) {
                    659:                                fatalexit = 2;
                    660:                                fatal("invalid type: %s\n", optarg);
                    661:                        }
                    662:                        if (!lookup->rdtypeset ||
                    663:                            lookup->rdtype != dns_rdatatype_axfr)
                    664:                                lookup->rdtype = rdtype;
                    665:                        lookup->rdtypeset = ISC_TRUE;
                    666:                        if (rdtype == dns_rdatatype_axfr) {
                    667:                                /* -l -t any -v */
                    668:                                list_type = dns_rdatatype_any;
                    669:                                short_form = ISC_FALSE;
                    670:                                lookup->tcp_mode = ISC_TRUE;
                    671:                        } else if (rdtype == dns_rdatatype_ixfr) {
                    672:                                lookup->ixfr_serial = serial;
                    673:                                lookup->tcp_mode = ISC_TRUE;
                    674:                                list_type = rdtype;
                    675:                        } else
                    676:                                list_type = rdtype;
                    677:                        list_addresses = ISC_FALSE;
                    678:                        default_lookups = ISC_FALSE;
                    679:                        break;
                    680:                case 'c':
                    681:                        tr.base = optarg;
                    682:                        tr.length = strlen(optarg);
                    683:                        result = dns_rdataclass_fromtext(&rdclass,
                    684:                                                   (isc_textregion_t *)&tr);
                    685:
                    686:                        if (result != ISC_R_SUCCESS) {
                    687:                                fatalexit = 2;
                    688:                                fatal("invalid class: %s\n", optarg);
                    689:                        } else {
                    690:                                lookup->rdclass = rdclass;
                    691:                                lookup->rdclassset = ISC_TRUE;
                    692:                        }
                    693:                        default_lookups = ISC_FALSE;
                    694:                        break;
                    695:                case 'a':
                    696:                        if (!lookup->rdtypeset ||
                    697:                            lookup->rdtype != dns_rdatatype_axfr)
                    698:                                lookup->rdtype = dns_rdatatype_any;
                    699:                        list_type = dns_rdatatype_any;
                    700:                        list_addresses = ISC_FALSE;
                    701:                        lookup->rdtypeset = ISC_TRUE;
                    702:                        short_form = ISC_FALSE;
                    703:                        default_lookups = ISC_FALSE;
                    704:                        break;
                    705:                case 'i':
                    706:                        lookup->ip6_int = ISC_TRUE;
                    707:                        break;
                    708:                case 'n':
                    709:                        /* deprecated */
                    710:                        break;
                    711:                case 'm':
                    712:                        /* Handled by pre_parse_args(). */
                    713:                        break;
                    714:                case 'w':
                    715:                        /*
                    716:                         * The timer routines are coded such that
                    717:                         * timeout==MAXINT doesn't enable the timer
                    718:                         */
                    719:                        timeout = INT_MAX;
                    720:                        break;
                    721:                case 'W':
                    722:                        timeout = strtonum(optarg, 0, INT_MAX, &errstr);
                    723:                        if (errstr != NULL)
                    724:                                errx(1, "timeout is %s: %s", errstr, optarg);
                    725:                        if (timeout < 1)
                    726:                                timeout = 1;
                    727:                        break;
                    728:                case 'R':
                    729:                        tries = strtonum(optarg, INT_MIN, INT_MAX - 1, &errstr);
                    730:                        if (errstr != NULL)
                    731:                                errx(1, "retries is %s: %s", errstr, optarg);
                    732:                        tries++;
                    733:                        if (tries < 2)
                    734:                                tries = 2;
                    735:                        break;
                    736:                case 'T':
                    737:                        lookup->tcp_mode = ISC_TRUE;
                    738:                        break;
                    739:                case 'C':
                    740:                        debug("showing all SOAs");
                    741:                        lookup->rdtype = dns_rdatatype_ns;
                    742:                        lookup->rdtypeset = ISC_TRUE;
                    743:                        lookup->rdclass = dns_rdataclass_in;
                    744:                        lookup->rdclassset = ISC_TRUE;
                    745:                        lookup->ns_search_only = ISC_TRUE;
                    746:                        lookup->trace_root = ISC_TRUE;
                    747:                        lookup->identify_previous_line = ISC_TRUE;
                    748:                        default_lookups = ISC_FALSE;
                    749:                        break;
                    750:                case 'N':
                    751:                        debug("setting NDOTS to %s", optarg);
                    752:                        ndots = strtonum(optarg, 0, INT_MAX, &errstr);
                    753:                        if (errstr != NULL)
                    754:                                errx(1, "ndots is %s: %s", errstr, optarg);
                    755:                        break;
                    756:                case 'D':
                    757:                        /* Handled by pre_parse_args(). */
                    758:                        break;
                    759:                case '4':
                    760:                        /* Handled by pre_parse_args(). */
                    761:                        break;
                    762:                case '6':
                    763:                        /* Handled by pre_parse_args(). */
                    764:                        break;
                    765:                case 's':
                    766:                        lookup->servfail_stops = ISC_TRUE;
                    767:                        break;
                    768:                default:
                    769:                        show_usage();
                    770:                }
                    771:        }
                    772:
                    773:        lookup->retries = tries;
                    774:
                    775:        argc -= optind;
                    776:        argv += optind;
                    777:
                    778:        if (argc == 0)
                    779:                show_usage();
                    780:
1.5       florian   781:        strlcpy(hostname, argv[0], sizeof(hostname));
1.1       florian   782:
1.5       florian   783:        if (argc >= 2) {
                    784:                set_nameserver(argv[1]);
1.1       florian   785:                debug("server is %s", *argv + 1);
                    786:                listed_server = ISC_TRUE;
                    787:        } else
                    788:                check_ra = ISC_TRUE;
                    789:
                    790:        lookup->pending = ISC_FALSE;
                    791:        if (get_reverse(store, sizeof(store), hostname,
                    792:                        lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
                    793:                strlcpy(lookup->textname, store, sizeof(lookup->textname));
                    794:                lookup->rdtype = dns_rdatatype_ptr;
                    795:                lookup->rdtypeset = ISC_TRUE;
                    796:                default_lookups = ISC_FALSE;
                    797:        } else {
                    798:                strlcpy(lookup->textname, hostname, sizeof(lookup->textname));
                    799:                usesearch = ISC_TRUE;
                    800:        }
                    801:        lookup->new_search = ISC_TRUE;
                    802:        ISC_LIST_APPEND(lookup_list, lookup, link);
                    803: }
                    804:
                    805: int
                    806: host_main(int argc, char **argv) {
                    807:        isc_result_t result;
                    808:
                    809:        tries = 2;
                    810:
                    811:        ISC_LIST_INIT(lookup_list);
                    812:        ISC_LIST_INIT(server_list);
1.4       florian   813:        ISC_LIST_INIT(root_hints_server_list);
1.1       florian   814:        ISC_LIST_INIT(search_list);
                    815:
                    816:        fatalexit = 1;
                    817:
                    818:        /* setup dighost callbacks */
                    819:        dighost_printmessage = printmessage;
                    820:        dighost_received = received;
                    821:        dighost_trying = trying;
                    822:        dighost_shutdown = host_shutdown;
                    823:
                    824:        debug("main()");
                    825:        progname = argv[0];
                    826:        pre_parse_args(argc, argv);
                    827:        result = isc_app_start();
                    828:        check_result(result, "isc_app_start");
                    829:
                    830:        if (pledge("stdio rpath inet dns", NULL) == -1) {
                    831:                perror("pledge");
                    832:                exit(1);
                    833:        }
                    834:
                    835:        setup_libs();
                    836:
                    837:        if (pledge("stdio inet dns", NULL) == -1) {
                    838:                perror("pledge");
                    839:                exit(1);
                    840:        }
                    841:
                    842:        parse_args(argc, argv);
                    843:        setup_system(ipv4only, ipv6only);
                    844:        result = isc_app_onrun(global_task, onrun_callback, NULL);
                    845:        check_result(result, "isc_app_onrun");
                    846:        isc_app_run();
                    847:        cancel_all();
                    848:        destroy_libs();
                    849:        return ((seen_error == 0) ? 0 : 1);
                    850: }