static isc_boolean_t dash_option(char *option, char *next, dig_lookup_t **lookup, isc_boolean_t *open_type_class, isc_boolean_t *need_clone, isc_boolean_t config_only, int argc, char **argv, isc_boolean_t *firstarg) { char opt, *value, *ptr, *ptr2, *ptr3; isc_result_t result; isc_boolean_t value_from_next; isc_textregion_t tr; dns_rdatatype_t rdtype; dns_rdataclass_t rdclass; char textname[MXNAME]; struct in_addr in4; struct in6_addr in6; in_port_t srcport; char *hash, *cmd; isc_uint32_t num; while (strpbrk(option, single_dash_opts) == &option[0]) { /* * Since the -[46dhimnv] options do not take an argument, * account for them (in any number and/or combination) * if they appear as the first character(s) of a q-opt. */ opt = option[0]; switch (opt) { case '4': if (have_ipv4) { isc_net_disableipv6(); have_ipv6 = ISC_FALSE; } else { fatal("can't find IPv4 networking"); /* NOTREACHED */ return (ISC_FALSE); } break; case '6': if (have_ipv6) { isc_net_disableipv4(); have_ipv4 = ISC_FALSE; } else { fatal("can't find IPv6 networking"); /* NOTREACHED */ return (ISC_FALSE); } break; case 'd': ptr = strpbrk(&option[1], dash_opts); if (ptr != &option[1]) { cmd = option; FULLCHECK("debug"); debugging = ISC_TRUE; return (ISC_FALSE); } else debugging = ISC_TRUE; break; case 'h': help(); exit(0); break; case 'i': ip6_int = ISC_TRUE; break; case 'm': /* memdebug */ /* memdebug is handled in preparse_args() */ break; case 'n': /* deprecated */ break; case 'v': version(); exit(0); break; } if (strlen(option) > 1U) option = &option[1]; else return (ISC_FALSE); } opt = option[0]; if (strlen(option) > 1U) { value_from_next = ISC_FALSE; value = &option[1]; } else { value_from_next = ISC_TRUE; value = next; } if (value == NULL) goto invalid_option; switch (opt) { case 'b': hash = strchr(value, '#'); if (hash != NULL) { result = parse_uint(&num, hash + 1, MAXPORT, "port number"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse port number"); srcport = num; *hash = '\0'; } else srcport = 0; if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { isc_sockaddr_fromin6(&bind_address, &in6, srcport); isc_net_disableipv4(); } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { isc_sockaddr_fromin(&bind_address, &in4, srcport); isc_net_disableipv6(); } else { if (hash != NULL) *hash = '#'; fatal("invalid address %s", value); } if (hash != NULL) *hash = '#'; specified_source = ISC_TRUE; return (value_from_next); case 'c': if ((*lookup)->rdclassset) { fprintf(stderr, ";; Warning, extra class option\n"); } *open_type_class = ISC_FALSE; tr.base = value; tr.length = strlen(value); result = dns_rdataclass_fromtext(&rdclass, (isc_textregion_t *)&tr); if (result == ISC_R_SUCCESS) { (*lookup)->rdclass = rdclass; (*lookup)->rdclassset = ISC_TRUE; } else fprintf(stderr, ";; Warning, ignoring " "invalid class %s\n", value); return (value_from_next); case 'f': batchname = value; return (value_from_next); case 'k': strncpy(keyfile, value, sizeof(keyfile)); keyfile[sizeof(keyfile)-1]=0; return (value_from_next); case 'p': result = parse_uint(&num, value, MAXPORT, "port number"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse port number"); port = num; return (value_from_next); case 'q': if (!config_only) { if (*need_clone) (*lookup) = clone_lookup(default_lookup, ISC_TRUE); *need_clone = ISC_TRUE; strncpy((*lookup)->textname, value, sizeof((*lookup)->textname)); (*lookup)->textname[sizeof((*lookup)->textname)-1]=0; (*lookup)->trace_root = ISC_TF((*lookup)->trace || (*lookup)->ns_search_only); (*lookup)->new_search = ISC_TRUE; if (*firstarg) { printgreeting(argc, argv, *lookup); *firstarg = ISC_FALSE; } ISC_LIST_APPEND(lookup_list, (*lookup), link); debug("looking up %s", (*lookup)->textname); } return (value_from_next); case 't': *open_type_class = ISC_FALSE; if (strncasecmp(value, "ixfr=", 5) == 0) { rdtype = dns_rdatatype_ixfr; result = ISC_R_SUCCESS; } else { tr.base = value; tr.length = strlen(value); result = dns_rdatatype_fromtext(&rdtype, (isc_textregion_t *)&tr); if (result == ISC_R_SUCCESS && rdtype == dns_rdatatype_ixfr) { result = DNS_R_UNKNOWN; } } if (result == ISC_R_SUCCESS) { if ((*lookup)->rdtypeset) { fprintf(stderr, ";; Warning, " "extra type option\n"); } if (rdtype == dns_rdatatype_ixfr) { isc_uint32_t serial; (*lookup)->rdtype = dns_rdatatype_ixfr; (*lookup)->rdtypeset = ISC_TRUE; result = parse_uint(&serial, &value[5], MAXSERIAL, "serial number"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse serial number"); (*lookup)->ixfr_serial = serial; (*lookup)->section_question = plusquest; (*lookup)->comments = pluscomm; (*lookup)->tcp_mode = ISC_TRUE; } else { (*lookup)->rdtype = rdtype; (*lookup)->rdtypeset = ISC_TRUE; if (rdtype == dns_rdatatype_axfr) { (*lookup)->section_question = plusquest; (*lookup)->comments = pluscomm; } (*lookup)->ixfr_serial = ISC_FALSE; } } else fprintf(stderr, ";; Warning, ignoring " "invalid type %s\n", value); return (value_from_next); case 'y': ptr = next_token(&value,":"); /* hmac type or name */ if (ptr == NULL) { usage(); } ptr2 = next_token(&value, ":"); /* name or secret */ if (ptr2 == NULL) usage(); ptr3 = next_token(&value,":"); /* secret or NULL */ if (ptr3 != NULL) { parse_hmac(ptr); ptr = ptr2; ptr2 = ptr3; } else { hmacname = DNS_TSIG_HMACMD5_NAME; digestbits = 0; } strncpy(keynametext, ptr, sizeof(keynametext)); keynametext[sizeof(keynametext)-1]=0; strncpy(keysecret, ptr2, sizeof(keysecret)); keysecret[sizeof(keysecret)-1]=0; return (value_from_next); case 'x': if (*need_clone) *lookup = clone_lookup(default_lookup, ISC_TRUE); *need_clone = ISC_TRUE; if (get_reverse(textname, sizeof(textname), value, ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { strncpy((*lookup)->textname, textname, sizeof((*lookup)->textname)); debug("looking up %s", (*lookup)->textname); (*lookup)->trace_root = ISC_TF((*lookup)->trace || (*lookup)->ns_search_only); (*lookup)->ip6_int = ip6_int; if (!(*lookup)->rdtypeset) (*lookup)->rdtype = dns_rdatatype_ptr; if (!(*lookup)->rdclassset) (*lookup)->rdclass = dns_rdataclass_in; (*lookup)->new_search = ISC_TRUE; if (*firstarg) { printgreeting(argc, argv, *lookup); *firstarg = ISC_FALSE; } ISC_LIST_APPEND(lookup_list, *lookup, link); } else { fprintf(stderr, "Invalid IP address %s\n", value); exit(1); } return (value_from_next); invalid_option: default: fprintf(stderr, "Invalid option: -%s\n", option); usage(); } /* NOTREACHED */ return (ISC_FALSE); }
static void plus_option(char *option, isc_boolean_t is_batchfile, dig_lookup_t *lookup) { isc_result_t result; char option_store[256]; char *cmd, *value, *ptr; isc_uint32_t num; isc_boolean_t state = ISC_TRUE; #ifdef DIG_SIGCHASE size_t n; #endif strncpy(option_store, option, sizeof(option_store)); option_store[sizeof(option_store)-1]=0; ptr = option_store; cmd = next_token(&ptr,"="); if (cmd == NULL) { printf(";; Invalid option %s\n", option_store); return; } value = ptr; if (strncasecmp(cmd, "no", 2)==0) { cmd += 2; state = ISC_FALSE; } #define FULLCHECK(A) \ do { \ size_t _l = strlen(cmd); \ if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ goto invalid_option; \ } while (0) #define FULLCHECK2(A, B) \ do { \ size_t _l = strlen(cmd); \ if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ goto invalid_option; \ } while (0) switch (cmd[0]) { case 'a': switch (cmd[1]) { case 'a': /* aaonly / aaflag */ FULLCHECK2("aaonly", "aaflag"); lookup->aaonly = state; break; case 'd': switch (cmd[2]) { case 'd': /* additional */ FULLCHECK("additional"); lookup->section_additional = state; break; case 'f': /* adflag */ case '\0': /* +ad is a synonym for +adflag */ FULLCHECK("adflag"); lookup->adflag = state; break; default: goto invalid_option; } break; case 'l': /* all */ FULLCHECK("all"); lookup->section_question = state; lookup->section_authority = state; lookup->section_answer = state; lookup->section_additional = state; lookup->comments = state; rrcomments = state; lookup->stats = state; printcmd = state; break; case 'n': /* answer */ FULLCHECK("answer"); lookup->section_answer = state; break; case 'u': /* authority */ FULLCHECK("authority"); lookup->section_authority = state; break; default: goto invalid_option; } break; case 'b': switch (cmd[1]) { case 'e':/* besteffort */ FULLCHECK("besteffort"); lookup->besteffort = state; break; case 'u':/* bufsize */ FULLCHECK("bufsize"); if (value == NULL) goto need_value; if (!state) goto invalid_option; result = parse_uint(&num, value, COMMSIZE, "buffer size"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse buffer size"); lookup->udpsize = num; break; default: goto invalid_option; } break; case 'c': switch (cmd[1]) { case 'd':/* cdflag */ switch (cmd[2]) { case 'f': /* cdflag */ case '\0': /* +cd is a synonym for +cdflag */ FULLCHECK("cdflag"); lookup->cdflag = state; break; default: goto invalid_option; } break; case 'l': /* cl */ FULLCHECK("cl"); noclass = ISC_TF(!state); break; case 'm': /* cmd */ FULLCHECK("cmd"); printcmd = state; break; case 'o': /* comments */ FULLCHECK("comments"); lookup->comments = state; if (lookup == default_lookup) pluscomm = state; break; default: goto invalid_option; } break; case 'd': switch (cmd[1]) { case 'e': /* defname */ FULLCHECK("defname"); if (!lookup->trace) { usesearch = state; } break; case 'n': /* dnssec */ FULLCHECK("dnssec"); if (state && lookup->edns == -1) lookup->edns = 0; lookup->dnssec = state; break; case 'o': /* domain */ FULLCHECK("domain"); if (value == NULL) goto need_value; if (!state) goto invalid_option; strncpy(domainopt, value, sizeof(domainopt)); domainopt[sizeof(domainopt)-1] = '\0'; break; default: goto invalid_option; } break; case 'e': FULLCHECK("edns"); if (!state) { lookup->edns = -1; break; } if (value == NULL) { lookup->edns = 0; break; } result = parse_uint(&num, value, 255, "edns"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse edns"); lookup->edns = num; break; case 'f': /* fail */ FULLCHECK("fail"); lookup->servfail_stops = state; break; case 'i': switch (cmd[1]) { case 'd': /* identify */ FULLCHECK("identify"); lookup->identify = state; break; case 'g': /* ignore */ default: /* Inherits default for compatibility */ FULLCHECK("ignore"); lookup->ignore = ISC_TRUE; } break; case 'm': /* multiline */ FULLCHECK("multiline"); multiline = state; break; case 'n': switch (cmd[1]) { case 'd': /* ndots */ FULLCHECK("ndots"); if (value == NULL) goto need_value; if (!state) goto invalid_option; result = parse_uint(&num, value, MAXNDOTS, "ndots"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse ndots"); ndots = num; break; case 's': switch (cmd[2]) { case 'i': /* nsid */ FULLCHECK("nsid"); if (state && lookup->edns == -1) lookup->edns = 0; lookup->nsid = state; break; case 's': /* nssearch */ FULLCHECK("nssearch"); lookup->ns_search_only = state; if (state) { lookup->trace_root = ISC_TRUE; lookup->recurse = ISC_TRUE; lookup->identify = ISC_TRUE; lookup->stats = ISC_FALSE; lookup->comments = ISC_FALSE; rrcomments = ISC_FALSE; lookup->section_additional = ISC_FALSE; lookup->section_authority = ISC_FALSE; lookup->section_question = ISC_FALSE; lookup->rdtype = dns_rdatatype_ns; lookup->rdtypeset = ISC_TRUE; short_form = ISC_TRUE; } break; default: goto invalid_option; } break; default: goto invalid_option; } break; case 'o': FULLCHECK("onesoa"); onesoa = state; break; case 'q': switch (cmd[1]) { case 'r': /* qr */ FULLCHECK("qr"); qr = state; break; case 'u': /* question */ FULLCHECK("question"); lookup->section_question = state; if (lookup == default_lookup) plusquest = state; break; default: goto invalid_option; } break; case 'r': switch (cmd[1]) { case 'e': switch (cmd[2]) { case 'c': /* recurse */ FULLCHECK("recurse"); lookup->recurse = state; break; case 't': /* retry / retries */ FULLCHECK2("retry", "retries"); if (value == NULL) goto need_value; if (!state) goto invalid_option; result = parse_uint(&lookup->retries, value, MAXTRIES - 1, "retries"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse retries"); lookup->retries++; break; default: goto invalid_option; } break; case 'r': /* rrcomments */ FULLCHECK("rrcomments"); rrcomments = state; break; default: goto invalid_option; } break; case 's': switch (cmd[1]) { case 'e': /* search */ FULLCHECK("search"); if (!lookup->trace) { usesearch = state; } break; case 'h': if (cmd[2] != 'o') goto invalid_option; switch (cmd[3]) { case 'r': /* short */ FULLCHECK("short"); short_form = state; if (state) { printcmd = ISC_FALSE; lookup->section_additional = ISC_FALSE; lookup->section_answer = ISC_TRUE; lookup->section_authority = ISC_FALSE; lookup->section_question = ISC_FALSE; lookup->comments = ISC_FALSE; rrcomments = ISC_FALSE; lookup->stats = ISC_FALSE; } break; case 'w': /* showsearch */ FULLCHECK("showsearch"); if (!lookup->trace) { showsearch = state; usesearch = state; } break; default: goto invalid_option; } break; #ifdef DIG_SIGCHASE case 'i': /* sigchase */ FULLCHECK("sigchase"); lookup->sigchase = state; if (lookup->sigchase) lookup->dnssec = ISC_TRUE; break; #endif case 'p': /* split */ FULLCHECK("split"); if (value != NULL && !state) goto invalid_option; if (!state) { splitwidth = 0; break; } else if (value == NULL) break; result = parse_uint(&splitwidth, value, 1023, "split"); if (splitwidth % 4 != 0) { splitwidth = ((splitwidth + 3) / 4) * 4; fprintf(stderr, ";; Warning, split must be " "a multiple of 4; adjusting " "to %d\n", splitwidth); } /* * There is an adjustment done in the * totext_<rrtype>() functions which causes * splitwidth to shrink. This is okay when we're * using the default width but incorrect in this * case, so we correct for it */ if (splitwidth) splitwidth += 3; if (result != ISC_R_SUCCESS) fatal("Couldn't parse retries"); break; case 't': /* stats */ FULLCHECK("stats"); lookup->stats = state; break; default: goto invalid_option; } break; case 't': switch (cmd[1]) { case 'c': /* tcp */ FULLCHECK("tcp"); if (!is_batchfile) lookup->tcp_mode = state; break; case 'i': /* timeout */ FULLCHECK("timeout"); if (value == NULL) goto need_value; if (!state) goto invalid_option; result = parse_uint(&timeout, value, MAXTIMEOUT, "timeout"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse timeout"); if (timeout == 0) timeout = 1; break; #if DIG_SIGCHASE_TD case 'o': /* topdown */ FULLCHECK("topdown"); lookup->do_topdown = state; break; #endif case 'r': switch (cmd[2]) { case 'a': /* trace */ FULLCHECK("trace"); lookup->trace = state; lookup->trace_root = state; if (state) { lookup->recurse = ISC_FALSE; lookup->identify = ISC_TRUE; lookup->comments = ISC_FALSE; rrcomments = ISC_FALSE; lookup->stats = ISC_FALSE; lookup->section_additional = ISC_FALSE; lookup->section_authority = ISC_TRUE; lookup->section_question = ISC_FALSE; lookup->dnssec = ISC_TRUE; usesearch = ISC_FALSE; } break; case 'i': /* tries */ FULLCHECK("tries"); if (value == NULL) goto need_value; if (!state) goto invalid_option; result = parse_uint(&lookup->retries, value, MAXTRIES, "tries"); if (result != ISC_R_SUCCESS) fatal("Couldn't parse tries"); if (lookup->retries == 0) lookup->retries = 1; break; #ifdef DIG_SIGCHASE case 'u': /* trusted-key */ FULLCHECK("trusted-key"); if (value == NULL) goto need_value; if (!state) goto invalid_option; n = strlcpy(trustedkey, ptr, sizeof(trustedkey)); if (n >= sizeof(trustedkey)) fatal("trusted key too large"); break; #endif default: goto invalid_option; } break; case 't': /* ttlid */ FULLCHECK("ttlid"); nottl = ISC_TF(!state); break; default: goto invalid_option; } break; case 'v': FULLCHECK("vc"); if (!is_batchfile) lookup->tcp_mode = state; break; default: invalid_option: need_value: fprintf(stderr, "Invalid option: +%s\n", option); usage(); } return; }
static void plus_option(char *option) { isc_result_t result; char option_store[256]; char *cmd, *value, *ptr; isc_boolean_t state = ISC_TRUE; strlcpy(option_store, option, sizeof(option_store)); ptr = option_store; cmd = next_token(&ptr,"="); if (cmd == NULL) { printf(";; Invalid option %s\n", option_store); return; } value = ptr; if (strncasecmp(cmd, "no", 2)==0) { cmd += 2; state = ISC_FALSE; } #define FULLCHECK(A) \ do { \ size_t _l = strlen(cmd); \ if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ goto invalid_option; \ } while (/*CONSTCOND*/0) switch (cmd[0]) { case 'a': /* all */ FULLCHECK("all"); showcomments = state; rrcomments = state; showtrust = state; break; case 'c': switch (cmd[1]) { case 'd': /* cdflag */ FULLCHECK("cdflag"); cdflag = state; break; case 'l': /* class */ FULLCHECK("class"); noclass = ISC_TF(!state); break; case 'o': /* comments */ FULLCHECK("comments"); showcomments = state; break; case 'r': /* crypto */ FULLCHECK("crypto"); nocrypto = ISC_TF(!state); break; default: goto invalid_option; } break; case 'd': switch (cmd[1]) { case 'l': /* dlv */ FULLCHECK("dlv"); if (state && no_sigs) break; dlv_validation = state; if (value != NULL) { dlv_anchor = isc_mem_strdup(mctx, value); if (dlv_anchor == NULL) fatal("out of memory"); } break; case 'n': /* dnssec */ FULLCHECK("dnssec"); showdnssec = state; break; default: goto invalid_option; } break; case 'm': switch (cmd[1]) { case 't': /* mtrace */ message_trace = state; if (state) resolve_trace = state; break; case 'u': /* multiline */ FULLCHECK("multiline"); multiline = state; break; default: goto invalid_option; } break; case 'r': switch (cmd[1]) { case 'o': /* root */ FULLCHECK("root"); if (state && no_sigs) break; root_validation = state; if (value != NULL) { trust_anchor = isc_mem_strdup(mctx, value); if (trust_anchor == NULL) fatal("out of memory"); } break; case 'r': /* rrcomments */ FULLCHECK("rrcomments"); rrcomments = state; break; case 't': /* rtrace */ FULLCHECK("rtrace"); resolve_trace = state; break; default: goto invalid_option; } break; case 's': switch (cmd[1]) { case 'h': /* short */ FULLCHECK("short"); short_form = state; if (short_form) { multiline = ISC_FALSE; showcomments = ISC_FALSE; showtrust = ISC_FALSE; showdnssec = ISC_FALSE; } break; case 'p': /* split */ FULLCHECK("split"); if (value != NULL && !state) goto invalid_option; if (!state) { splitwidth = 0; break; } else if (value == NULL) break; result = parse_uint(&splitwidth, value, 1023, "split"); if (splitwidth % 4 != 0) { splitwidth = ((splitwidth + 3) / 4) * 4; warn("split must be a multiple of 4; " "adjusting to %d", splitwidth); } /* * There is an adjustment done in the * totext_<rrtype>() functions which causes * splitwidth to shrink. This is okay when we're * using the default width but incorrect in this * case, so we correct for it */ if (splitwidth) splitwidth += 3; if (result != ISC_R_SUCCESS) fatal("Couldn't parse split"); break; default: goto invalid_option; } break; case 't': switch (cmd[1]) { case 'r': /* trust */ FULLCHECK("trust"); showtrust = state; break; case 't': /* ttl */ FULLCHECK("ttl"); nottl = ISC_TF(!state); break; default: goto invalid_option; } break; case 'v': /* vtrace */ FULLCHECK("vtrace"); validator_trace = state; if (state) resolve_trace = state; break; default: invalid_option: /* * We can also add a "need_value:" case here if we ever * add a plus-option that requires a specified value */ fprintf(stderr, "Invalid option: +%s\n", option); usage(); } return; }