[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.13

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