2015-02-05 07:56:05 +11:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2015-02-05 07:56:05 +11:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2020-09-14 16:20:40 -07:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2015-02-05 07:56:05 +11:00
|
|
|
*/
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <isc/app.h>
|
2018-08-07 16:46:53 +02:00
|
|
|
#include <isc/attributes.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <isc/base64.h>
|
|
|
|
#include <isc/hash.h>
|
|
|
|
#include <isc/hex.h>
|
|
|
|
#include <isc/log.h>
|
2021-04-27 00:07:43 +02:00
|
|
|
#include <isc/managers.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/net.h>
|
2021-01-14 13:02:57 -08:00
|
|
|
#include <isc/netmgr.h>
|
2018-05-28 15:22:23 +02:00
|
|
|
#include <isc/nonce.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <isc/parseint.h>
|
2015-02-05 13:25:38 +01:00
|
|
|
#include <isc/print.h>
|
2018-04-22 14:56:28 +02:00
|
|
|
#include <isc/random.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <isc/sockaddr.h>
|
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/task.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/byaddr.h>
|
|
|
|
#include <dns/dispatch.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/events.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/rdata.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/rdataclass.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/request.h>
|
|
|
|
#include <dns/resolver.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/result.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
#include <dns/types.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/view.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dst/result.h>
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-03-09 16:17:26 +01:00
|
|
|
#include <bind9/getaddresses.h>
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#define CHECK(str, x) \
|
|
|
|
{ \
|
|
|
|
if ((x) != ISC_R_SUCCESS) { \
|
|
|
|
fprintf(stderr, "mdig: %s failed with %s\n", (str), \
|
|
|
|
isc_result_totext(x)); \
|
|
|
|
exit(-1); \
|
|
|
|
} \
|
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#define ADD_STRING(b, s) \
|
|
|
|
{ \
|
|
|
|
if (strlen(s) >= isc_buffer_availablelength(b)) \
|
2020-02-13 21:48:23 +01:00
|
|
|
return ((ISC_R_NOSPACE)); \
|
2020-02-12 13:59:18 +01:00
|
|
|
else \
|
|
|
|
isc_buffer_putstr(b, s); \
|
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define MXNAME (DNS_NAME_MAXTEXT + 1)
|
|
|
|
#define COMMSIZE 0xffff
|
|
|
|
#define OUTPUTBUF 32767
|
|
|
|
#define MAXPORT 0xffff
|
|
|
|
#define PORT 53
|
2015-02-05 07:56:05 +11:00
|
|
|
#define MAXTIMEOUT 0xffff
|
|
|
|
#define TCPTIMEOUT 10
|
|
|
|
#define UDPTIMEOUT 5
|
2020-02-13 14:44:37 -08:00
|
|
|
#define MAXTRIES 0xffffffff
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-09-16 12:40:52 +10:00
|
|
|
#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */
|
|
|
|
#define US_PER_SEC 1000000 /*%< Microseconds per second. */
|
|
|
|
#define US_PER_MS 1000 /*%< Microseconds per millisecond. */
|
|
|
|
|
2021-05-19 17:18:22 -07:00
|
|
|
static isc_mem_t *mctx = NULL;
|
|
|
|
static dns_requestmgr_t *requestmgr = NULL;
|
|
|
|
static const char *batchname = NULL;
|
|
|
|
static FILE *batchfp = NULL;
|
2020-09-16 12:40:52 +10:00
|
|
|
static bool burst = false;
|
2020-02-13 14:44:37 -08:00
|
|
|
static bool have_ipv4 = false;
|
|
|
|
static bool have_ipv6 = false;
|
|
|
|
static bool have_src = false;
|
|
|
|
static bool tcp_mode = false;
|
|
|
|
static bool besteffort = true;
|
|
|
|
static bool display_short_form = false;
|
|
|
|
static bool display_headers = true;
|
|
|
|
static bool display_comments = true;
|
|
|
|
static int display_rrcomments = 0;
|
|
|
|
static bool display_ttlunits = true;
|
|
|
|
static bool display_ttl = true;
|
|
|
|
static bool display_class = true;
|
|
|
|
static bool display_crypto = true;
|
|
|
|
static bool display_multiline = false;
|
|
|
|
static bool display_question = true;
|
|
|
|
static bool display_answer = true;
|
|
|
|
static bool display_authority = true;
|
|
|
|
static bool display_additional = true;
|
|
|
|
static bool display_unknown_format = false;
|
|
|
|
static bool yaml = false;
|
|
|
|
static bool continue_on_error = false;
|
|
|
|
static uint32_t display_splitwidth = 0xffffffff;
|
|
|
|
static isc_sockaddr_t srcaddr;
|
2021-05-19 17:18:22 -07:00
|
|
|
static char *server = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
static isc_sockaddr_t dstaddr;
|
|
|
|
static in_port_t port = 53;
|
|
|
|
static isc_dscp_t dscp = -1;
|
|
|
|
static unsigned char cookie_secret[33];
|
|
|
|
static int onfly = 0;
|
|
|
|
static char hexcookie[81];
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
struct query {
|
2020-02-13 21:48:23 +01:00
|
|
|
char textname[MXNAME]; /*% Name we're going to be
|
|
|
|
* looking up */
|
2020-02-13 14:44:37 -08:00
|
|
|
bool recurse;
|
|
|
|
bool have_aaonly;
|
|
|
|
bool have_adflag;
|
|
|
|
bool have_cdflag;
|
|
|
|
bool have_zflag;
|
|
|
|
bool dnssec;
|
|
|
|
bool expire;
|
|
|
|
bool send_cookie;
|
|
|
|
char *cookie;
|
|
|
|
bool nsid;
|
|
|
|
dns_rdatatype_t rdtype;
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_rdataclass_t rdclass;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint16_t udpsize;
|
|
|
|
int16_t edns;
|
|
|
|
dns_ednsopt_t *ednsopts;
|
|
|
|
unsigned int ednsoptscnt;
|
|
|
|
unsigned int ednsflags;
|
|
|
|
isc_sockaddr_t *ecs_addr;
|
|
|
|
unsigned int timeout;
|
|
|
|
unsigned int udptimeout;
|
|
|
|
unsigned int udpretries;
|
2015-02-05 07:56:05 +11:00
|
|
|
ISC_LINK(struct query) link;
|
|
|
|
};
|
|
|
|
static struct query default_query;
|
|
|
|
static ISC_LIST(struct query) queries;
|
|
|
|
|
|
|
|
#define EDNSOPTS 100U
|
|
|
|
/*% opcode text */
|
2020-02-12 13:59:18 +01:00
|
|
|
static const char *const opcodetext[] = {
|
|
|
|
"QUERY", "IQUERY", "STATUS", "RESERVED3",
|
|
|
|
"NOTIFY", "UPDATE", "RESERVED6", "RESERVED7",
|
|
|
|
"RESERVED8", "RESERVED9", "RESERVED10", "RESERVED11",
|
|
|
|
"RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15"
|
2015-02-05 07:56:05 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
/*% return code text */
|
2020-02-12 13:59:18 +01:00
|
|
|
static const char *const rcodetext[] = {
|
|
|
|
"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP",
|
|
|
|
"REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH",
|
|
|
|
"NOTZONE", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14",
|
|
|
|
"RESERVED15", "BADVERS"
|
2015-02-05 07:56:05 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
/*% safe rcodetext[] */
|
|
|
|
static char *
|
2020-02-13 14:44:37 -08:00
|
|
|
rcode_totext(dns_rcode_t rcode) {
|
2015-02-05 07:56:05 +11:00
|
|
|
static char buf[sizeof("?65535")];
|
|
|
|
union {
|
|
|
|
const char *consttext;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *deconsttext;
|
2015-02-05 07:56:05 +11:00
|
|
|
} totext;
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) {
|
2015-02-05 07:56:05 +11:00
|
|
|
snprintf(buf, sizeof(buf), "?%u", rcode);
|
|
|
|
totext.deconsttext = buf;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-02-05 07:56:05 +11:00
|
|
|
totext.consttext = rcodetext[rcode];
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
return (totext.deconsttext);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/* receive response event handler */
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
recvresponse(isc_task_t *task, isc_event_t *event) {
|
|
|
|
dns_requestevent_t *reqev = (dns_requestevent_t *)event;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_message_t *query = NULL, *response = NULL;
|
|
|
|
unsigned int parseflags = 0;
|
|
|
|
isc_buffer_t *msgbuf = NULL, *buf = NULL;
|
|
|
|
unsigned int len = OUTPUTBUF;
|
|
|
|
dns_master_style_t *style = NULL;
|
|
|
|
unsigned int styleflags = 0;
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_messagetextflag_t flags;
|
|
|
|
|
|
|
|
UNUSED(task);
|
|
|
|
|
|
|
|
REQUIRE(reqev != NULL);
|
2016-09-28 15:02:36 +02:00
|
|
|
query = reqev->ev_arg;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
if (reqev->result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "response failed with %s\n",
|
|
|
|
isc_result_totext(reqev->result));
|
2020-02-13 21:48:23 +01:00
|
|
|
if (continue_on_error) {
|
2016-09-28 15:02:36 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2016-09-28 15:02:36 +02:00
|
|
|
exit(-1);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
2020-09-25 11:51:36 +02:00
|
|
|
dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
parseflags |= DNS_MESSAGEPARSE_PRESERVEORDER;
|
|
|
|
if (besteffort) {
|
|
|
|
parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
|
|
|
|
parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
|
|
|
|
}
|
2019-07-20 14:35:59 -04:00
|
|
|
|
|
|
|
msgbuf = dns_request_getanswer(reqev->request);
|
2015-02-05 07:56:05 +11:00
|
|
|
result = dns_request_getresponse(reqev->request, response, parseflags);
|
|
|
|
CHECK("dns_request_getresponse", result);
|
|
|
|
|
|
|
|
styleflags |= DNS_STYLEFLAG_REL_OWNER;
|
2019-07-20 14:35:59 -04:00
|
|
|
if (yaml) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_YAML;
|
2019-11-18 20:46:58 +11:00
|
|
|
response->indent.string = " ";
|
|
|
|
response->indent.count = 3;
|
2019-07-20 14:35:59 -04:00
|
|
|
} else {
|
|
|
|
if (display_comments) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_COMMENT;
|
|
|
|
}
|
|
|
|
if (display_unknown_format) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
|
|
|
|
}
|
|
|
|
if (display_rrcomments > 0) {
|
2019-07-30 12:28:20 -07:00
|
|
|
styleflags |= DNS_STYLEFLAG_RRCOMMENT;
|
|
|
|
}
|
2019-07-20 14:35:59 -04:00
|
|
|
if (display_ttlunits) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_TTL_UNITS;
|
|
|
|
}
|
|
|
|
if (!display_ttl) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_NO_TTL;
|
|
|
|
}
|
|
|
|
if (!display_class) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_NO_CLASS;
|
|
|
|
}
|
|
|
|
if (!display_crypto) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_NOCRYPTO;
|
|
|
|
}
|
|
|
|
if (display_multiline) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
|
|
|
|
styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
|
|
|
|
styleflags |= DNS_STYLEFLAG_REL_DATA;
|
|
|
|
styleflags |= DNS_STYLEFLAG_OMIT_TTL;
|
|
|
|
styleflags |= DNS_STYLEFLAG_TTL;
|
|
|
|
styleflags |= DNS_STYLEFLAG_MULTILINE;
|
|
|
|
styleflags |= DNS_STYLEFLAG_COMMENT;
|
|
|
|
/* Turn on rrcomments unless explicitly disabled */
|
|
|
|
if (display_rrcomments >= 0) {
|
|
|
|
styleflags |= DNS_STYLEFLAG_RRCOMMENT;
|
|
|
|
}
|
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (display_multiline || (!display_ttl && !display_class)) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_master_stylecreate(&style, styleflags, 24, 24, 24,
|
|
|
|
32, 80, 8, display_splitwidth,
|
|
|
|
mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (!display_ttl || !display_class) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_master_stylecreate(&style, styleflags, 24, 24, 32,
|
|
|
|
40, 80, 8, display_splitwidth,
|
|
|
|
mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_master_stylecreate(&style, styleflags, 24, 32, 40,
|
|
|
|
48, 80, 8, display_splitwidth,
|
|
|
|
mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_master_stylecreate2", result);
|
|
|
|
|
|
|
|
flags = 0;
|
|
|
|
if (!display_headers) {
|
|
|
|
flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
|
|
|
|
flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!display_comments) {
|
2015-02-05 07:56:05 +11:00
|
|
|
flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(mctx, &buf, len);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2019-07-20 14:35:59 -04:00
|
|
|
if (yaml) {
|
2020-02-13 14:44:37 -08:00
|
|
|
char sockstr[ISC_SOCKADDR_FORMATSIZE];
|
2019-07-20 14:35:59 -04:00
|
|
|
uint16_t sport;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *hash;
|
|
|
|
int pf;
|
2019-07-20 14:35:59 -04:00
|
|
|
|
|
|
|
printf("-\n");
|
|
|
|
printf(" type: MESSAGE\n");
|
|
|
|
printf(" message:\n");
|
|
|
|
|
|
|
|
if (((response->flags & DNS_MESSAGEFLAG_RD) != 0) &&
|
2020-02-13 14:44:37 -08:00
|
|
|
((response->flags & DNS_MESSAGEFLAG_RA) != 0))
|
|
|
|
{
|
2019-07-20 14:35:59 -04:00
|
|
|
printf(" type: RECURSIVE_RESPONSE\n");
|
|
|
|
} else {
|
|
|
|
printf(" type: AUTH_RESPONSE\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" message_size: %ub\n",
|
|
|
|
isc_buffer_usedlength(msgbuf));
|
|
|
|
|
|
|
|
pf = isc_sockaddr_pf(&dstaddr);
|
|
|
|
if (pf == PF_INET || pf == PF_INET6) {
|
|
|
|
printf(" socket_family: %s\n",
|
|
|
|
pf == PF_INET ? "INET" : "INET6");
|
|
|
|
|
|
|
|
printf(" socket_protocol: %s\n",
|
|
|
|
tcp_mode ? "TCP" : "UDP");
|
|
|
|
|
|
|
|
sport = isc_sockaddr_getport(&dstaddr);
|
|
|
|
isc_sockaddr_format(&dstaddr, sockstr, sizeof(sockstr));
|
|
|
|
hash = strchr(sockstr, '#');
|
|
|
|
if (hash != NULL) {
|
|
|
|
*hash = '\0';
|
|
|
|
}
|
|
|
|
printf(" response_address: %s\n", sockstr);
|
|
|
|
printf(" response_port: %u\n", sport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (have_src) {
|
|
|
|
sport = isc_sockaddr_getport(&srcaddr);
|
|
|
|
isc_sockaddr_format(&srcaddr, sockstr, sizeof(sockstr));
|
|
|
|
hash = strchr(sockstr, '#');
|
|
|
|
if (hash != NULL) {
|
|
|
|
*hash = '\0';
|
|
|
|
}
|
|
|
|
printf(" query_address: %s\n", sockstr);
|
|
|
|
printf(" query_port: %u\n", sport);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" %s:\n", "response_message_data");
|
|
|
|
result = dns_message_headertotext(response, style, flags, buf);
|
2019-09-06 11:38:39 +10:00
|
|
|
CHECK("dns_message_headertotext", result);
|
2019-07-20 14:35:59 -04:00
|
|
|
} else if (display_comments && !display_short_form) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(";; Got answer:\n");
|
2015-02-05 13:34:18 +01:00
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
if (display_headers) {
|
|
|
|
printf(";; ->>HEADER<<- opcode: %s, status: %s, "
|
|
|
|
"id: %u\n",
|
|
|
|
opcodetext[response->opcode],
|
2020-02-12 13:59:18 +01:00
|
|
|
rcode_totext(response->rcode), response->id);
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(";; flags:");
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_QR) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" qr");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_AA) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" aa");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_TC) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" tc");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_RD) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" rd");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_RA) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" ra");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_AD) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" ad");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_CD) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(" cd");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if ((response->flags & 0x0040U) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
printf("; MBZ: 0x4");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
printf("; QUERY: %u, ANSWER: %u, "
|
|
|
|
"AUTHORITY: %u, ADDITIONAL: %u\n",
|
|
|
|
response->counts[DNS_SECTION_QUESTION],
|
|
|
|
response->counts[DNS_SECTION_ANSWER],
|
|
|
|
response->counts[DNS_SECTION_AUTHORITY],
|
|
|
|
response->counts[DNS_SECTION_ADDITIONAL]);
|
|
|
|
|
|
|
|
if ((response->flags & DNS_MESSAGEFLAG_RD) != 0 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(response->flags & DNS_MESSAGEFLAG_RA) == 0)
|
|
|
|
{
|
2015-02-05 07:56:05 +11:00
|
|
|
printf(";; WARNING: recursion requested "
|
|
|
|
"but not available\n");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
repopulate_buffer:
|
|
|
|
|
|
|
|
if (display_comments && display_headers && !display_short_form) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_pseudosectiontotext(
|
|
|
|
response, DNS_PSEUDOSECTION_OPT, style, flags, buf);
|
2015-02-05 07:56:05 +11:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2020-02-12 13:59:18 +01:00
|
|
|
buftoosmall:
|
2015-02-05 07:56:05 +11:00
|
|
|
len += OUTPUTBUF;
|
|
|
|
isc_buffer_free(&buf);
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(mctx, &buf, len);
|
|
|
|
goto repopulate_buffer;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
CHECK("dns_message_pseudosectiontotext", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_question && display_headers && !display_short_form) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_sectiontotext(
|
|
|
|
response, DNS_SECTION_QUESTION, style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_sectiontotext", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_answer && !display_short_form) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_sectiontotext(response, DNS_SECTION_ANSWER,
|
2015-02-05 07:56:05 +11:00
|
|
|
style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_sectiontotext", result);
|
|
|
|
} else if (display_answer) {
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *name;
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_rdataset_t *rdataset;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t loopresult;
|
|
|
|
dns_name_t empty_name;
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
unsigned int answerstyleflags = 0;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!display_crypto) {
|
2015-02-05 07:56:05 +11:00
|
|
|
answerstyleflags |= DNS_STYLEFLAG_NOCRYPTO;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (display_unknown_format) {
|
2016-02-09 15:38:34 +05:30
|
|
|
answerstyleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
dns_name_init(&empty_name, NULL);
|
|
|
|
result = dns_message_firstname(response, DNS_SECTION_ANSWER);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_NOMORE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_firstname", result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
for (;;) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOMORE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_nextname", result);
|
|
|
|
name = NULL;
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_message_currentname(response, DNS_SECTION_ANSWER,
|
2015-02-05 07:56:05 +11:00
|
|
|
&name);
|
|
|
|
|
|
|
|
for (rdataset = ISC_LIST_HEAD(name->list);
|
|
|
|
rdataset != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link))
|
|
|
|
{
|
2015-02-05 07:56:05 +11:00
|
|
|
loopresult = dns_rdataset_first(rdataset);
|
|
|
|
while (loopresult == ISC_R_SUCCESS) {
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
result = dns_rdata_tofmttext(
|
2020-02-12 13:59:18 +01:00
|
|
|
&rdata, NULL, answerstyleflags,
|
|
|
|
0, 60, " ", buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_rdata_tofmttext", result);
|
|
|
|
loopresult =
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_rdataset_next(rdataset);
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
if (strlen("\n") >=
|
2020-02-13 21:48:23 +01:00
|
|
|
isc_buffer_availablelength(buf)) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_buffer_putstr(buf, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = dns_message_nextname(response,
|
|
|
|
DNS_SECTION_ANSWER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_authority && !display_short_form) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_sectiontotext(
|
|
|
|
response, DNS_SECTION_AUTHORITY, style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_sectiontotext", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_additional && !display_short_form) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_sectiontotext(
|
|
|
|
response, DNS_SECTION_ADDITIONAL, style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_sectiontotext", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_additional && !display_short_form && display_headers) {
|
|
|
|
/*
|
|
|
|
* Only print the signature on the first record.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_pseudosectiontotext(
|
|
|
|
response, DNS_PSEUDOSECTION_TSIG, style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_pseudosectiontotext", result);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_pseudosectiontotext(
|
|
|
|
response, DNS_PSEUDOSECTION_SIG0, style, flags, buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto buftoosmall;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_pseudosectiontotext", result);
|
|
|
|
}
|
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
if (display_headers && display_comments && !display_short_form && !yaml)
|
|
|
|
{
|
2015-02-05 07:56:05 +11:00
|
|
|
printf("\n");
|
2019-07-20 14:35:59 -04:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
printf("%.*s", (int)isc_buffer_usedlength(buf),
|
|
|
|
(char *)isc_buffer_base(buf));
|
|
|
|
isc_buffer_free(&buf);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
fflush(stdout);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (style != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_master_styledestroy(&style, mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query != NULL) {
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&query);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (response != NULL) {
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&response);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_request_destroy(&reqev->request);
|
|
|
|
isc_event_free(&event);
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (--onfly == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_app_shutdown();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Add EDNS0 option record to a message. Currently, the only supported
|
|
|
|
* options are UDP buffer size, the DO bit, and EDNS options
|
2015-07-06 09:44:24 +10:00
|
|
|
* (e.g., NSID, COOKIE, client-subnet)
|
2015-02-05 07:56:05 +11:00
|
|
|
*/
|
|
|
|
static void
|
2020-02-12 13:59:18 +01:00
|
|
|
add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_ednsopt_t *opts, size_t count) {
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_rdataset_t *rdataset = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
|
2018-03-19 17:31:53 +00:00
|
|
|
opts, count);
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_message_buildopt", result);
|
|
|
|
result = dns_message_setopt(msg, rdataset);
|
|
|
|
CHECK("dns_message_setopt", result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
compute_cookie(unsigned char *cookie, size_t len) {
|
2015-02-05 07:56:05 +11:00
|
|
|
/* XXXMPA need to fix, should be per server. */
|
|
|
|
INSIST(len >= 8U);
|
|
|
|
memmove(cookie, cookie_secret, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
sendquery(struct query *query, isc_task_t *task) {
|
2021-05-19 17:18:22 -07:00
|
|
|
dns_request_t *request = NULL;
|
|
|
|
dns_message_t *message = NULL;
|
|
|
|
dns_name_t *qname = NULL;
|
|
|
|
dns_rdataset_t *qrdataset = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_fixedname_t queryname;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t buf;
|
|
|
|
unsigned int options;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
onfly++;
|
|
|
|
|
|
|
|
dns_fixedname_init(&queryname);
|
|
|
|
isc_buffer_init(&buf, query->textname, strlen(query->textname));
|
|
|
|
isc_buffer_add(&buf, strlen(query->textname));
|
|
|
|
result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
|
|
|
|
dns_rootname, 0, NULL);
|
|
|
|
CHECK("dns_name_fromtext", result);
|
|
|
|
|
2020-09-25 11:51:36 +02:00
|
|
|
dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
message->opcode = dns_opcode_query;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->recurse) {
|
2015-02-05 07:56:05 +11:00
|
|
|
message->flags |= DNS_MESSAGEFLAG_RD;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query->have_aaonly) {
|
2015-02-05 07:56:05 +11:00
|
|
|
message->flags |= DNS_MESSAGEFLAG_AA;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query->have_adflag) {
|
2015-02-05 07:56:05 +11:00
|
|
|
message->flags |= DNS_MESSAGEFLAG_AD;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query->have_cdflag) {
|
2015-02-05 07:56:05 +11:00
|
|
|
message->flags |= DNS_MESSAGEFLAG_CD;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query->have_zflag) {
|
2015-02-05 07:56:05 +11:00
|
|
|
message->flags |= 0x0040U;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
message->rdclass = query->rdclass;
|
|
|
|
message->id = (unsigned short)(random() & 0xFFFF);
|
|
|
|
|
|
|
|
result = dns_message_gettempname(message, &qname);
|
|
|
|
CHECK("dns_message_gettempname", result);
|
|
|
|
|
|
|
|
result = dns_message_gettemprdataset(message, &qrdataset);
|
|
|
|
CHECK("dns_message_gettemprdataset", result);
|
|
|
|
|
|
|
|
dns_name_clone(dns_fixedname_name(&queryname), qname);
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_rdataset_makequestion(qrdataset, query->rdclass, query->rdtype);
|
2015-02-05 07:56:05 +11:00
|
|
|
ISC_LIST_APPEND(qname->list, qrdataset, link);
|
|
|
|
dns_message_addname(message, qname, DNS_SECTION_QUESTION);
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
if (query->udpsize > 0 || query->dnssec || query->edns > -1 ||
|
2020-02-13 14:44:37 -08:00
|
|
|
query->ecs_addr != NULL)
|
|
|
|
{
|
2015-02-05 07:56:05 +11:00
|
|
|
dns_ednsopt_t opts[EDNSOPTS + DNS_EDNSOPTIONS];
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int flags;
|
|
|
|
int i = 0;
|
|
|
|
char ecsbuf[20];
|
2015-07-06 09:44:24 +10:00
|
|
|
unsigned char cookie[40];
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->udpsize == 0) {
|
2020-09-30 18:18:05 +02:00
|
|
|
query->udpsize = 1232;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (query->edns < 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->edns = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
if (query->nsid) {
|
|
|
|
INSIST(i < DNS_EDNSOPTIONS);
|
|
|
|
opts[i].code = DNS_OPT_NSID;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->ecs_addr != NULL) {
|
2020-02-13 14:44:37 -08:00
|
|
|
uint8_t addr[16], family;
|
|
|
|
uint32_t plen;
|
|
|
|
struct sockaddr *sa;
|
|
|
|
struct sockaddr_in *sin;
|
2015-02-05 07:56:05 +11:00
|
|
|
struct sockaddr_in6 *sin6;
|
2020-02-13 14:44:37 -08:00
|
|
|
size_t addrl;
|
|
|
|
isc_buffer_t b;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
sa = &query->ecs_addr->type.sa;
|
2016-01-29 17:41:29 -08:00
|
|
|
plen = query->ecs_addr->length;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
/* Round up prefix len to a multiple of 8 */
|
2016-01-29 17:41:29 -08:00
|
|
|
addrl = (plen + 7) / 8;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
INSIST(i < DNS_EDNSOPTIONS);
|
|
|
|
opts[i].code = DNS_OPT_CLIENT_SUBNET;
|
2020-02-12 13:59:18 +01:00
|
|
|
opts[i].length = (uint16_t)addrl + 4;
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("isc_buffer_allocate", result);
|
|
|
|
isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
|
|
|
|
if (sa->sa_family == AF_INET) {
|
2016-01-29 17:41:29 -08:00
|
|
|
family = 1;
|
2020-02-12 13:59:18 +01:00
|
|
|
sin = (struct sockaddr_in *)sa;
|
2016-03-23 08:54:46 -07:00
|
|
|
memmove(addr, &sin->sin_addr, 4);
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((plen % 8) != 0) {
|
2020-02-12 13:59:18 +01:00
|
|
|
addr[addrl - 1] &= ~0U
|
|
|
|
<< (8 - (plen % 8));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
} else {
|
2016-01-29 17:41:29 -08:00
|
|
|
family = 2;
|
2020-02-12 13:59:18 +01:00
|
|
|
sin6 = (struct sockaddr_in6 *)sa;
|
2016-03-23 08:54:46 -07:00
|
|
|
memmove(addr, &sin6->sin6_addr, 16);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
2016-01-29 17:41:29 -08:00
|
|
|
/* Mask off last address byte */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (addrl > 0 && (plen % 8) != 0) {
|
2016-07-13 13:54:12 +05:30
|
|
|
addr[addrl - 1] &= ~0U << (8 - (plen % 8));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-01-29 17:41:29 -08:00
|
|
|
|
|
|
|
/* family */
|
|
|
|
isc_buffer_putuint16(&b, family);
|
|
|
|
/* source prefix-length */
|
|
|
|
isc_buffer_putuint8(&b, plen);
|
|
|
|
/* scope prefix-length */
|
|
|
|
isc_buffer_putuint8(&b, 0);
|
|
|
|
/* address */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (addrl > 0) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_putmem(&b, addr, (unsigned)addrl);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-01-29 17:41:29 -08:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
opts[i].value = (uint8_t *)ecsbuf;
|
2015-02-05 07:56:05 +11:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
if (query->send_cookie) {
|
2015-02-05 07:56:05 +11:00
|
|
|
INSIST(i < DNS_EDNSOPTIONS);
|
2015-07-06 09:44:24 +10:00
|
|
|
opts[i].code = DNS_OPT_COOKIE;
|
|
|
|
if (query->cookie != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_buffer_t b;
|
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_buffer_init(&b, cookie, sizeof(cookie));
|
2020-02-13 14:44:37 -08:00
|
|
|
result = isc_hex_decodestring(query->cookie,
|
|
|
|
&b);
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("isc_hex_decodestring", result);
|
|
|
|
opts[i].value = isc_buffer_base(&b);
|
|
|
|
opts[i].length = isc_buffer_usedlength(&b);
|
|
|
|
} else {
|
2015-07-06 09:44:24 +10:00
|
|
|
compute_cookie(cookie, 8);
|
2015-02-05 07:56:05 +11:00
|
|
|
opts[i].length = 8;
|
|
|
|
opts[i].value = cookie;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->expire) {
|
|
|
|
INSIST(i < DNS_EDNSOPTIONS);
|
|
|
|
opts[i].code = DNS_OPT_EXPIRE;
|
|
|
|
opts[i].length = 0;
|
|
|
|
opts[i].value = NULL;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->ednsoptscnt != 0) {
|
|
|
|
memmove(&opts[i], query->ednsopts,
|
|
|
|
sizeof(dns_ednsopt_t) * query->ednsoptscnt);
|
|
|
|
i += query->ednsoptscnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = query->ednsflags;
|
|
|
|
flags &= ~DNS_MESSAGEEXTFLAG_DO;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->dnssec) {
|
2015-02-05 07:56:05 +11:00
|
|
|
flags |= DNS_MESSAGEEXTFLAG_DO;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
add_opt(message, query->udpsize, query->edns, flags, opts, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
options = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (tcp_mode) {
|
2020-12-11 15:20:33 -08:00
|
|
|
options |= DNS_REQUESTOPT_TCP;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
request = NULL;
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_request_createvia(
|
|
|
|
requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, dscp,
|
|
|
|
options, NULL, query->timeout, query->udptimeout,
|
|
|
|
query->udpretries, task, recvresponse, message, &request);
|
2020-12-09 15:45:13 -08:00
|
|
|
CHECK("dns_request_createvia", result);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
return (ISC_R_SUCCESS);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
sendqueries(isc_task_t *task, isc_event_t *event) {
|
2015-02-05 07:56:05 +11:00
|
|
|
struct query *query = (struct query *)event->ev_arg;
|
|
|
|
|
|
|
|
isc_event_free(&event);
|
|
|
|
|
|
|
|
while (query != NULL) {
|
|
|
|
struct query *next = ISC_LIST_NEXT(query, link);
|
|
|
|
|
|
|
|
sendquery(query, task);
|
|
|
|
query = next;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (onfly == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_app_shutdown();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-07 16:46:53 +02:00
|
|
|
ISC_NORETURN static void
|
|
|
|
usage(void);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
usage(void) {
|
2020-04-02 18:51:06 -07:00
|
|
|
fprintf(stderr, "Usage: mdig @server {global-opt} host\n"
|
|
|
|
" {local-opt} [ host {local-opt} [...]]\n"
|
|
|
|
"\nUse \"mdig -h\" (or \"mdig -h | more\") "
|
|
|
|
"for complete list of options\n");
|
2015-02-05 07:56:05 +11:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*% help */
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
help(void) {
|
2020-04-02 18:51:06 -07:00
|
|
|
printf("Usage: mdig @server {global-opt} host\n"
|
|
|
|
" {local-opt} [ host {local-opt} [...]]\n"
|
|
|
|
"Where:\n"
|
|
|
|
" anywhere opt is one of:\n"
|
|
|
|
" -f filename (batch mode)\n"
|
|
|
|
" -h (print help and exit)\n"
|
|
|
|
" -v (print version and exit)\n"
|
|
|
|
" global opt is one of:\n"
|
|
|
|
" -4 (use IPv4 query transport "
|
|
|
|
"only)\n"
|
|
|
|
" -6 (use IPv6 query transport "
|
|
|
|
"only)\n"
|
|
|
|
" -b address[#port] (bind to source "
|
|
|
|
"address/port)\n"
|
|
|
|
" -p port (specify port number)\n"
|
|
|
|
" -m (enable memory usage "
|
|
|
|
"debugging)\n"
|
|
|
|
" +[no]dscp[=###] (Set the DSCP value to "
|
|
|
|
"### "
|
|
|
|
"[0..63])\n"
|
|
|
|
" +[no]vc (TCP mode)\n"
|
|
|
|
" +[no]tcp (TCP mode, alternate "
|
|
|
|
"syntax)\n"
|
|
|
|
" +[no]besteffort (Try to parse even "
|
|
|
|
"illegal "
|
|
|
|
"messages)\n"
|
|
|
|
" +[no]cl (Control display of class "
|
|
|
|
"in records)\n"
|
|
|
|
" +[no]comments (Control display of "
|
|
|
|
"comment lines)\n"
|
|
|
|
" +[no]rrcomments (Control display of "
|
|
|
|
"per-record "
|
|
|
|
"comments)\n"
|
|
|
|
" +[no]crypto (Control display of "
|
|
|
|
"cryptographic "
|
|
|
|
"fields in records)\n"
|
|
|
|
" +[no]question (Control display of "
|
|
|
|
"question)\n"
|
|
|
|
" +[no]answer (Control display of "
|
|
|
|
"answer)\n"
|
|
|
|
" +[no]authority (Control display of "
|
|
|
|
"authority)\n"
|
|
|
|
" +[no]additional (Control display of "
|
|
|
|
"additional)\n"
|
|
|
|
" +[no]short (Disable everything "
|
|
|
|
"except "
|
|
|
|
"short\n"
|
|
|
|
" form of answer)\n"
|
|
|
|
" +[no]ttlid (Control display of ttls "
|
|
|
|
"in records)\n"
|
|
|
|
" +[no]ttlunits (Display TTLs in "
|
|
|
|
"human-readable units)\n"
|
|
|
|
" +[no]unknownformat (Print RDATA in RFC 3597 "
|
|
|
|
"\"unknown\" format)\n"
|
|
|
|
" +[no]all (Set or clear all display "
|
|
|
|
"flags)\n"
|
|
|
|
" +[no]multiline (Print records in an "
|
|
|
|
"expanded format)\n"
|
|
|
|
" +[no]split=## (Split hex/base64 fields "
|
|
|
|
"into chunks)\n"
|
|
|
|
" local opt is one of:\n"
|
|
|
|
" -c class (specify query class)\n"
|
|
|
|
" -t type (specify query type)\n"
|
|
|
|
" -x dot-notation (shortcut for reverse "
|
|
|
|
"lookups)\n"
|
|
|
|
" +timeout=### (Set query timeout) "
|
|
|
|
"[UDP=5,TCP=10]\n"
|
|
|
|
" +udptimeout=### (Set timeout before UDP "
|
|
|
|
"retry)\n"
|
|
|
|
" +tries=### (Set number of UDP "
|
|
|
|
"attempts) [3]\n"
|
|
|
|
" +retry=### (Set number of UDP "
|
|
|
|
"retries) [2]\n"
|
|
|
|
" +bufsize=### (Set EDNS0 Max UDP packet "
|
|
|
|
"size)\n"
|
|
|
|
" +subnet=addr (Set edns-client-subnet "
|
|
|
|
"option)\n"
|
|
|
|
" +[no]edns[=###] (Set EDNS version) [0]\n"
|
|
|
|
" +ednsflags=### (Set EDNS flag bits)\n"
|
|
|
|
" +ednsopt=###[:value] (Send specified EDNS "
|
|
|
|
"option)\n"
|
|
|
|
" +noednsopt (Clear list of +ednsopt "
|
|
|
|
"options)\n"
|
|
|
|
" +[no]recurse (Recursive mode)\n"
|
|
|
|
" +[no]aaonly (Set AA flag in query "
|
|
|
|
"(+[no]aaflag))\n"
|
|
|
|
" +[no]adflag (Set AD flag in query)\n"
|
|
|
|
" +[no]cdflag (Set CD flag in query)\n"
|
|
|
|
" +[no]zflag (Set Z flag in query)\n"
|
|
|
|
" +[no]dnssec (Request DNSSEC records)\n"
|
|
|
|
" +[no]expire (Request time to expire)\n"
|
|
|
|
" +[no]cookie[=###] (Send a COOKIE option)\n"
|
|
|
|
" +[no]nsid (Request Name "
|
|
|
|
"Server ID)\n");
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
2018-08-07 16:46:53 +02:00
|
|
|
ISC_NORETURN static void
|
|
|
|
fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
fatal(const char *format, ...) {
|
2015-02-05 07:56:05 +11:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, "mdig: ");
|
|
|
|
va_start(args, format);
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
exit(-2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2018-03-28 14:19:37 +02:00
|
|
|
parse_uint_helper(uint32_t *uip, const char *value, uint32_t max,
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *desc, int base) {
|
|
|
|
uint32_t n;
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_result_t result = isc_parse_uint32(&n, value, base);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS && n > max) {
|
2015-02-05 07:56:05 +11:00
|
|
|
result = ISC_R_RANGE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
printf("invalid %s '%s': %s\n", desc, value,
|
|
|
|
isc_result_totext(result));
|
2015-02-05 07:56:05 +11:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
*uip = n;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2015-02-05 07:56:05 +11:00
|
|
|
return (parse_uint_helper(uip, value, max, desc, 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
|
2015-02-05 07:56:05 +11:00
|
|
|
return (parse_uint_helper(uip, value, max, desc, 0));
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:38:24 +10:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
newopts(struct query *query) {
|
2018-08-23 10:19:43 +02:00
|
|
|
size_t len = sizeof(query->ednsopts[0]) * EDNSOPTS;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
query->ednsopts = isc_mem_allocate(mctx, len);
|
|
|
|
|
|
|
|
for (i = 0; i < EDNSOPTS; i++) {
|
|
|
|
query->ednsopts[i].code = 0;
|
|
|
|
query->ednsopts[i].length = 0;
|
|
|
|
query->ednsopts[i].value = NULL;
|
|
|
|
}
|
2018-07-12 12:38:24 +10:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
save_opt(struct query *query, char *code, char *value) {
|
|
|
|
uint32_t num;
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_buffer_t b;
|
|
|
|
isc_result_t result;
|
|
|
|
|
2018-07-12 12:38:24 +10:00
|
|
|
if (query->ednsopts == NULL) {
|
|
|
|
newopts(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query->ednsoptscnt == EDNSOPTS) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("too many ednsopts");
|
2018-07-12 12:38:24 +10:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
result = parse_uint(&num, code, 65535, "ednsopt");
|
2018-07-12 12:38:24 +10:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("bad edns code point: %s", code);
|
2018-07-12 12:38:24 +10:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2018-07-12 12:38:24 +10:00
|
|
|
query->ednsopts[query->ednsoptscnt].code = num;
|
|
|
|
query->ednsopts[query->ednsoptscnt].length = 0;
|
|
|
|
query->ednsopts[query->ednsoptscnt].value = NULL;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
if (value != NULL) {
|
|
|
|
char *buf;
|
2019-07-23 10:56:26 -04:00
|
|
|
buf = isc_mem_allocate(mctx, strlen(value) / 2 + 1);
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_init(&b, buf, strlen(value) / 2 + 1);
|
2015-02-05 07:56:05 +11:00
|
|
|
result = isc_hex_decodestring(value, &b);
|
|
|
|
CHECK("isc_hex_decodestring", result);
|
2020-02-12 13:59:18 +01:00
|
|
|
query->ednsopts[query->ednsoptscnt].value = isc_buffer_base(&b);
|
2018-07-12 12:38:24 +10:00
|
|
|
query->ednsopts[query->ednsoptscnt].length =
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_usedlength(&b);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
query->ednsoptscnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_sockaddr_t *sa = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
struct in_addr in4;
|
2015-02-05 07:56:05 +11:00
|
|
|
struct in6_addr in6;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t netmask = 0xffffffff;
|
|
|
|
char *slash = NULL;
|
|
|
|
bool parsed = false;
|
2015-11-20 18:38:24 +11:00
|
|
|
char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf)) {
|
2015-11-20 18:38:24 +11:00
|
|
|
fatal("invalid prefix '%s'\n", value);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-11-20 18:38:24 +11:00
|
|
|
|
|
|
|
slash = strchr(buf, '/');
|
|
|
|
if (slash != NULL) {
|
2019-08-08 13:52:44 +10:00
|
|
|
isc_result_t result;
|
2016-01-29 17:41:29 -08:00
|
|
|
*slash = '\0';
|
2015-02-05 07:56:05 +11:00
|
|
|
result = isc_parse_uint32(&netmask, slash + 1, 10);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("invalid prefix length in '%s': %s\n", value,
|
|
|
|
isc_result_totext(result));
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
2016-01-27 19:00:36 -08:00
|
|
|
} else if (strcmp(value, "0") == 0) {
|
|
|
|
netmask = 0;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
sa = isc_mem_allocate(mctx, sizeof(*sa));
|
2015-11-20 18:38:24 +11:00
|
|
|
if (inet_pton(AF_INET6, buf, &in6) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2015-11-20 18:38:24 +11:00
|
|
|
isc_sockaddr_fromin6(sa, &in6, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (netmask > 128) {
|
2015-02-05 07:56:05 +11:00
|
|
|
netmask = 128;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-11-20 18:38:24 +11:00
|
|
|
} else if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (netmask > 32) {
|
2015-02-05 07:56:05 +11:00
|
|
|
netmask = 32;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-01-27 19:00:36 -08:00
|
|
|
} else if (netmask != 0xffffffff) {
|
2015-02-05 07:56:05 +11:00
|
|
|
int i;
|
|
|
|
|
2016-01-29 17:41:29 -08:00
|
|
|
for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
|
2015-02-05 07:56:05 +11:00
|
|
|
strlcat(buf, ".0", sizeof(buf));
|
2015-02-05 13:34:18 +01:00
|
|
|
if (inet_pton(AF_INET, buf, &in4) == 1) {
|
2018-04-17 08:29:14 -07:00
|
|
|
parsed = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_sockaddr_fromin(sa, &in4, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (netmask > 32) {
|
2016-01-27 19:00:36 -08:00
|
|
|
netmask = 32;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!parsed) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("invalid address '%s'", value);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
sa->length = netmask;
|
|
|
|
*sap = sa;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Append 'len' bytes of 'text' at '*p', failing with
|
|
|
|
* ISC_R_NOSPACE if that would advance p past 'end'.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
append(const char *text, int len, char **p, char *end) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (len > end - *p) {
|
2015-02-05 07:56:05 +11:00
|
|
|
return (ISC_R_NOSPACE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
memmove(*p, text, len);
|
|
|
|
*p += len;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
reverse_octets(const char *in, char **p, char *end) {
|
2015-11-20 18:38:24 +11:00
|
|
|
const char *dot = strchr(in, '.');
|
2020-02-13 14:44:37 -08:00
|
|
|
int len;
|
2015-02-05 07:56:05 +11:00
|
|
|
if (dot != NULL) {
|
|
|
|
isc_result_t result;
|
|
|
|
result = reverse_octets(dot + 1, p, end);
|
|
|
|
CHECK("reverse_octets", result);
|
|
|
|
result = append(".", 1, p, end);
|
|
|
|
CHECK("append", result);
|
|
|
|
len = (int)(dot - in);
|
|
|
|
} else {
|
|
|
|
len = strlen(in);
|
|
|
|
}
|
|
|
|
return (append(in, len, p, end));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
get_reverse(char *reverse, size_t len, const char *value) {
|
|
|
|
int r;
|
|
|
|
isc_result_t result;
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_netaddr_t addr;
|
|
|
|
|
|
|
|
addr.family = AF_INET6;
|
2015-02-05 13:34:18 +01:00
|
|
|
r = inet_pton(AF_INET6, value, &addr.type.in6);
|
2015-02-05 07:56:05 +11:00
|
|
|
if (r > 0) {
|
|
|
|
/* This is a valid IPv6 address. */
|
|
|
|
dns_fixedname_t fname;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *name;
|
|
|
|
unsigned int options = 0;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fname);
|
2018-04-03 13:10:07 +02:00
|
|
|
result = dns_byaddr_createptrname(&addr, options, name);
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("dns_byaddr_createptrname2", result);
|
|
|
|
dns_name_format(name, reverse, (unsigned int)len);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Not a valid IPv6 address. Assume IPv4.
|
|
|
|
* Construct the in-addr.arpa name by blindly
|
|
|
|
* reversing octets whether or not they look like
|
|
|
|
* integers, so that this can be used for RFC2317
|
|
|
|
* names and such.
|
|
|
|
*/
|
|
|
|
char *p = reverse;
|
|
|
|
char *end = reverse + len;
|
|
|
|
result = reverse_octets(value, &p, end);
|
|
|
|
CHECK("reverse_octets", result);
|
|
|
|
/* Append .in-addr.arpa. and a terminating NUL. */
|
|
|
|
result = append(".in-addr.arpa.", 15, &p, end);
|
|
|
|
CHECK("append", result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* We're not using isc_commandline_parse() here since the command line
|
|
|
|
* syntax of mdig is quite a bit different from that which can be described
|
|
|
|
* by that routine.
|
|
|
|
* XXX doc options
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
plus_option(char *option, struct query *query, bool global) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *cmd, *value, *last = NULL, *code;
|
|
|
|
uint32_t num;
|
|
|
|
bool state = true;
|
|
|
|
size_t n;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2018-05-01 16:03:46 +10:00
|
|
|
INSIST(option != NULL);
|
|
|
|
|
2018-03-21 21:08:29 +00:00
|
|
|
if ((cmd = strtok_r(option, "=", &last)) == NULL) {
|
|
|
|
printf(";; Invalid option %s\n", option);
|
2015-02-05 07:56:05 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (strncasecmp(cmd, "no", 2) == 0) {
|
|
|
|
cmd += 2;
|
2018-04-17 08:29:14 -07:00
|
|
|
state = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
2018-03-21 21:08:29 +00:00
|
|
|
/* parse the rest of the string */
|
|
|
|
value = strtok_r(NULL, "", &last);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#define FULLCHECK(A) \
|
|
|
|
do { \
|
|
|
|
size_t _l = strlen(cmd); \
|
2015-02-05 07:56:05 +11:00
|
|
|
if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
|
2020-02-12 13:59:18 +01:00
|
|
|
goto invalid_option; \
|
2015-02-05 07:56:05 +11:00
|
|
|
} while (0)
|
2020-02-12 13:59:18 +01:00
|
|
|
#define FULLCHECK2(A, B) \
|
|
|
|
do { \
|
|
|
|
size_t _l = strlen(cmd); \
|
2015-02-05 07:56:05 +11:00
|
|
|
if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
|
2020-02-12 13:59:18 +01:00
|
|
|
(_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
|
|
|
|
goto invalid_option; \
|
2015-02-05 07:56:05 +11:00
|
|
|
} while (0)
|
2020-02-12 13:59:18 +01:00
|
|
|
#define GLOBAL() \
|
|
|
|
do { \
|
|
|
|
if (!global) \
|
2015-02-05 07:56:05 +11:00
|
|
|
goto global_option; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
switch (cmd[0]) {
|
|
|
|
case 'a':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'a': /* aaonly / aaflag */
|
|
|
|
FULLCHECK2("aaonly", "aaflag");
|
|
|
|
query->have_aaonly = state;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
switch (cmd[2]) {
|
|
|
|
case 'd': /* additional */
|
|
|
|
FULLCHECK("additional");
|
|
|
|
display_additional = state;
|
|
|
|
break;
|
2020-02-12 13:59:18 +01:00
|
|
|
case 'f': /* adflag */
|
2015-02-05 07:56:05 +11:00
|
|
|
case '\0': /* +ad is a synonym for +adflag */
|
|
|
|
FULLCHECK("adflag");
|
|
|
|
query->have_adflag = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'l': /* all */
|
|
|
|
FULLCHECK("all");
|
|
|
|
GLOBAL();
|
|
|
|
display_question = state;
|
|
|
|
display_answer = state;
|
|
|
|
display_authority = state;
|
|
|
|
display_additional = state;
|
|
|
|
display_comments = state;
|
2019-07-30 12:28:20 -07:00
|
|
|
display_rrcomments = state ? 1 : -1;
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
case 'n': /* answer */
|
|
|
|
FULLCHECK("answer");
|
|
|
|
GLOBAL();
|
|
|
|
display_answer = state;
|
|
|
|
break;
|
|
|
|
case 'u': /* authority */
|
|
|
|
FULLCHECK("authority");
|
|
|
|
GLOBAL();
|
|
|
|
display_authority = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
switch (cmd[1]) {
|
2020-02-12 13:59:18 +01:00
|
|
|
case 'e': /* besteffort */
|
2015-02-05 07:56:05 +11:00
|
|
|
FULLCHECK("besteffort");
|
|
|
|
GLOBAL();
|
|
|
|
besteffort = state;
|
|
|
|
break;
|
2020-09-16 12:40:52 +10:00
|
|
|
case 'u':
|
|
|
|
switch (cmd[2]) {
|
|
|
|
case 'f': /* bufsize */
|
|
|
|
FULLCHECK("bufsize");
|
|
|
|
if (value == NULL) {
|
|
|
|
goto need_value;
|
|
|
|
}
|
|
|
|
if (!state) {
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
result = parse_uint(&num, value, COMMSIZE,
|
|
|
|
"buffer size");
|
|
|
|
CHECK("parse_uint(buffer size)", result);
|
|
|
|
query->udpsize = num;
|
|
|
|
break;
|
|
|
|
case 'r': /* burst */
|
|
|
|
FULLCHECK("burst");
|
|
|
|
GLOBAL();
|
|
|
|
burst = state;
|
|
|
|
break;
|
|
|
|
default:
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
switch (cmd[1]) {
|
2020-02-12 13:59:18 +01:00
|
|
|
case 'd': /* cdflag */
|
2015-02-05 07:56:05 +11:00
|
|
|
switch (cmd[2]) {
|
2020-02-12 13:59:18 +01:00
|
|
|
case 'f': /* cdflag */
|
2015-02-05 07:56:05 +11:00
|
|
|
case '\0': /* +cd is a synonym for +cdflag */
|
|
|
|
FULLCHECK("cdflag");
|
|
|
|
query->have_cdflag = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'l': /* cl */
|
|
|
|
FULLCHECK("cl");
|
|
|
|
GLOBAL();
|
|
|
|
display_class = state;
|
|
|
|
break;
|
|
|
|
case 'o': /* comments */
|
2015-07-06 09:44:24 +10:00
|
|
|
switch (cmd[2]) {
|
|
|
|
case 'm':
|
|
|
|
FULLCHECK("comments");
|
|
|
|
GLOBAL();
|
|
|
|
display_comments = state;
|
|
|
|
break;
|
2016-09-28 15:02:36 +02:00
|
|
|
case 'n':
|
|
|
|
FULLCHECK("continue");
|
|
|
|
GLOBAL();
|
|
|
|
continue_on_error = state;
|
|
|
|
break;
|
2015-07-06 09:44:24 +10:00
|
|
|
case 'o':
|
|
|
|
FULLCHECK("cookie");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (state && query->edns == -1) {
|
2015-07-06 09:44:24 +10:00
|
|
|
query->edns = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
query->send_cookie = state;
|
|
|
|
if (value != NULL) {
|
|
|
|
n = strlcpy(hexcookie, value,
|
|
|
|
sizeof(hexcookie));
|
2020-02-13 21:48:23 +01:00
|
|
|
if (n >= sizeof(hexcookie)) {
|
2015-07-06 09:44:24 +10:00
|
|
|
fatal("COOKIE data too large");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
query->cookie = hexcookie;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-07-06 09:44:24 +10:00
|
|
|
query->cookie = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
FULLCHECK("crypto");
|
|
|
|
GLOBAL();
|
|
|
|
display_crypto = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'n': /* dnssec */
|
|
|
|
FULLCHECK("dnssec");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (state && query->edns == -1) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->edns = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
query->dnssec = state;
|
|
|
|
break;
|
|
|
|
case 's': /* dscp */
|
|
|
|
FULLCHECK("dscp");
|
|
|
|
GLOBAL();
|
|
|
|
if (!state) {
|
|
|
|
dscp = -1;
|
|
|
|
break;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
result = parse_uint(&num, value, 0x3f, "DSCP");
|
|
|
|
CHECK("parse_uint(DSCP)", result);
|
|
|
|
dscp = num;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'd':
|
2020-02-12 13:59:18 +01:00
|
|
|
switch (cmd[2]) {
|
2015-02-05 07:56:05 +11:00
|
|
|
case 'n':
|
|
|
|
switch (cmd[3]) {
|
|
|
|
case 's':
|
|
|
|
switch (cmd[4]) {
|
|
|
|
case 0:
|
|
|
|
FULLCHECK("edns");
|
|
|
|
if (!state) {
|
|
|
|
query->edns = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (value == NULL) {
|
|
|
|
query->edns = 0;
|
|
|
|
break;
|
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = parse_uint(&num, value,
|
2015-02-05 07:56:05 +11:00
|
|
|
255,
|
|
|
|
"edns");
|
|
|
|
CHECK("parse_uint(edns)",
|
|
|
|
result);
|
|
|
|
query->edns = num;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
FULLCHECK("ednsflags");
|
|
|
|
if (!state) {
|
|
|
|
query->ednsflags = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (value == NULL) {
|
|
|
|
query->ednsflags = 0;
|
|
|
|
break;
|
|
|
|
}
|
2020-02-17 12:05:39 -08:00
|
|
|
result = parse_xint(
|
|
|
|
&num, value, 0xffff,
|
|
|
|
"ednsflags");
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("parse_xint(ednsflags)",
|
|
|
|
result);
|
|
|
|
query->ednsflags = num;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
FULLCHECK("ednsopt");
|
|
|
|
if (!state) {
|
|
|
|
query->ednsoptscnt = 0;
|
|
|
|
break;
|
|
|
|
}
|
2018-07-12 12:38:24 +10:00
|
|
|
code = NULL;
|
|
|
|
if (value != NULL) {
|
|
|
|
code = strtok_r(value,
|
|
|
|
":",
|
|
|
|
&last);
|
|
|
|
}
|
|
|
|
if (code == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("ednsopt no "
|
|
|
|
"code point "
|
|
|
|
"specified");
|
2018-07-12 12:38:24 +10:00
|
|
|
}
|
|
|
|
value = strtok_r(NULL, "\0",
|
2018-08-23 10:19:43 +02:00
|
|
|
&last);
|
2015-02-05 07:56:05 +11:00
|
|
|
save_opt(query, code, value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
FULLCHECK("expire");
|
|
|
|
query->expire = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'm': /* multiline */
|
|
|
|
FULLCHECK("multiline");
|
|
|
|
GLOBAL();
|
|
|
|
display_multiline = state;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
FULLCHECK("nsid");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (state && query->edns == -1) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->edns = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
query->nsid = state;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
FULLCHECK("question");
|
|
|
|
GLOBAL();
|
|
|
|
display_question = state;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'e':
|
|
|
|
switch (cmd[2]) {
|
|
|
|
case 'c': /* recurse */
|
|
|
|
FULLCHECK("recurse");
|
|
|
|
query->recurse = state;
|
|
|
|
break;
|
|
|
|
case 't': /* retry / retries */
|
|
|
|
FULLCHECK2("retry", "retries");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!state) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = parse_uint(&query->udpretries, value,
|
|
|
|
MAXTRIES - 1, "udpretries");
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("parse_uint(udpretries)", result);
|
|
|
|
query->udpretries++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
FULLCHECK("rrcomments");
|
|
|
|
GLOBAL();
|
2019-07-30 12:28:20 -07:00
|
|
|
display_rrcomments = state ? 1 : -1;
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'h':
|
|
|
|
FULLCHECK("short");
|
|
|
|
GLOBAL();
|
|
|
|
display_short_form = state;
|
|
|
|
if (state) {
|
2018-04-17 08:29:14 -07:00
|
|
|
display_question = false;
|
|
|
|
display_answer = true;
|
|
|
|
display_authority = false;
|
|
|
|
display_additional = false;
|
|
|
|
display_comments = false;
|
2019-07-30 12:28:20 -07:00
|
|
|
display_rrcomments = -1;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p': /* split */
|
|
|
|
FULLCHECK("split");
|
|
|
|
GLOBAL();
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value != NULL && !state) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
if (!state) {
|
|
|
|
display_splitwidth = 0;
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = parse_uint(&display_splitwidth, value, 1023,
|
|
|
|
"split");
|
2018-02-14 19:09:23 +11:00
|
|
|
if ((display_splitwidth % 4) != 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
display_splitwidth =
|
2020-02-12 13:59:18 +01:00
|
|
|
((display_splitwidth + 3) / 4) * 4;
|
|
|
|
fprintf(stderr,
|
|
|
|
";; Warning, split must be "
|
|
|
|
"a multiple of 4; adjusting "
|
|
|
|
"to %u\n",
|
2015-02-05 07:56:05 +11:00
|
|
|
display_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
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (display_splitwidth) {
|
2015-02-05 07:56:05 +11:00
|
|
|
display_splitwidth += 3;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("parse_uint(split)", result);
|
|
|
|
break;
|
|
|
|
case 'u': /* subnet */
|
|
|
|
FULLCHECK("subnet");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (state && value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
if (!state) {
|
|
|
|
if (query->ecs_addr != NULL) {
|
|
|
|
isc_mem_free(mctx, query->ecs_addr);
|
|
|
|
query->ecs_addr = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->edns == -1) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->edns = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
result = parse_netprefix(&query->ecs_addr, value);
|
|
|
|
CHECK("parse_netprefix", result);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'c': /* tcp */
|
|
|
|
FULLCHECK("tcp");
|
|
|
|
GLOBAL();
|
|
|
|
tcp_mode = state;
|
|
|
|
break;
|
|
|
|
case 'i': /* timeout */
|
|
|
|
FULLCHECK("timeout");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!state) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = parse_uint(&query->timeout, value, MAXTIMEOUT,
|
|
|
|
"timeout");
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("parse_uint(timeout)", result);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->timeout == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->timeout = 1;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
FULLCHECK("tries");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!state) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = parse_uint(&query->udpretries, value, MAXTRIES,
|
|
|
|
"udpretries");
|
2015-02-05 07:56:05 +11:00
|
|
|
CHECK("parse_uint(udpretries)", result);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->udpretries == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->udpretries = 1;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
switch (cmd[2]) {
|
|
|
|
case 'l':
|
|
|
|
switch (cmd[3]) {
|
|
|
|
case 0:
|
|
|
|
case 'i': /* ttlid */
|
|
|
|
FULLCHECK2("ttl", "ttlid");
|
|
|
|
GLOBAL();
|
|
|
|
display_ttl = state;
|
|
|
|
break;
|
|
|
|
case 'u': /* ttlunits */
|
|
|
|
FULLCHECK("ttlunits");
|
|
|
|
GLOBAL();
|
2018-04-17 08:29:14 -07:00
|
|
|
display_ttl = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
display_ttlunits = state;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto invalid_option;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'u':
|
2016-02-09 15:38:34 +05:30
|
|
|
switch (cmd[1]) {
|
|
|
|
case 'd':
|
|
|
|
FULLCHECK("udptimeout");
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2016-02-09 15:38:34 +05:30
|
|
|
goto need_value;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!state) {
|
2016-02-09 15:38:34 +05:30
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-02-09 15:38:34 +05:30
|
|
|
result = parse_uint(&query->udptimeout, value,
|
|
|
|
MAXTIMEOUT, "udptimeout");
|
|
|
|
CHECK("parse_uint(udptimeout)", result);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
FULLCHECK("unknownformat");
|
|
|
|
display_unknown_format = state;
|
|
|
|
break;
|
|
|
|
default:
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2016-02-09 15:38:34 +05:30
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
FULLCHECK("vc");
|
|
|
|
GLOBAL();
|
|
|
|
tcp_mode = state;
|
|
|
|
break;
|
2019-07-20 14:35:59 -04:00
|
|
|
case 'y': /* yaml */
|
|
|
|
FULLCHECK("yaml");
|
|
|
|
yaml = state;
|
|
|
|
if (state) {
|
|
|
|
display_rrcomments = state;
|
|
|
|
}
|
|
|
|
break;
|
2015-02-05 07:56:05 +11:00
|
|
|
case 'z': /* zflag */
|
|
|
|
FULLCHECK("zflag");
|
|
|
|
query->have_zflag = state;
|
|
|
|
break;
|
|
|
|
global_option:
|
|
|
|
fprintf(stderr, "Ignored late global option: +%s\n", option);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
invalid_option:
|
|
|
|
need_value:
|
|
|
|
fprintf(stderr, "Invalid option: +%s\n", option);
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
2018-04-17 08:29:14 -07:00
|
|
|
* #true returned if value was used
|
2015-02-05 07:56:05 +11:00
|
|
|
*/
|
2017-01-24 17:48:31 +11:00
|
|
|
static const char *single_dash_opts = "46himv";
|
2018-11-06 11:59:04 +11:00
|
|
|
static const char *dash_opts = "46bcfhiptvx";
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2020-02-12 13:59:18 +01:00
|
|
|
dash_option(const char *option, char *next, struct query *query, bool global,
|
2020-02-13 14:44:37 -08:00
|
|
|
bool *setname) {
|
|
|
|
char opt;
|
|
|
|
const char *value;
|
|
|
|
isc_result_t result;
|
|
|
|
bool value_from_next;
|
2015-11-20 18:38:24 +11:00
|
|
|
isc_consttextregion_t tr;
|
2020-02-13 14:44:37 -08:00
|
|
|
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;
|
|
|
|
uint32_t num;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
while (strpbrk(option, single_dash_opts) == &option[0]) {
|
|
|
|
/*
|
|
|
|
* Since the -[46hiv] options do not take an argument,
|
|
|
|
* account for them (in any number and/or combination)
|
|
|
|
* if they appear as the first character(s) of an opt.
|
|
|
|
*/
|
|
|
|
opt = option[0];
|
|
|
|
switch (opt) {
|
|
|
|
case '4':
|
|
|
|
GLOBAL();
|
|
|
|
if (have_ipv4) {
|
|
|
|
isc_net_disableipv6();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv6 = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
} else {
|
|
|
|
fatal("can't find IPv4 networking");
|
|
|
|
/* NOTREACHED */
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
GLOBAL();
|
|
|
|
if (have_ipv6) {
|
|
|
|
isc_net_disableipv4();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv4 = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
} else {
|
|
|
|
fatal("can't find IPv6 networking");
|
|
|
|
/* NOTREACHED */
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
help();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'i':
|
2018-11-02 14:23:01 +00:00
|
|
|
/* deprecated */
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
2017-01-24 17:48:31 +11:00
|
|
|
case 'm':
|
|
|
|
/*
|
|
|
|
* handled by preparse_args()
|
|
|
|
*/
|
|
|
|
break;
|
2015-02-05 07:56:05 +11:00
|
|
|
case 'v':
|
2018-08-07 16:46:53 +02:00
|
|
|
fprintf(stderr, "mDiG %s\n", PACKAGE_VERSION);
|
2015-02-05 07:56:05 +11:00
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strlen(option) > 1U) {
|
2015-02-05 07:56:05 +11:00
|
|
|
option = &option[1];
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
opt = option[0];
|
|
|
|
if (strlen(option) > 1U) {
|
2018-04-17 08:29:14 -07:00
|
|
|
value_from_next = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
value = &option[1];
|
|
|
|
} else {
|
2018-04-17 08:29:14 -07:00
|
|
|
value_from_next = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
value = next;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
goto invalid_option;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
switch (opt) {
|
|
|
|
case 'b':
|
|
|
|
GLOBAL();
|
|
|
|
hash = strchr(value, '#');
|
|
|
|
if (hash != NULL) {
|
|
|
|
result = parse_uint(&num, hash + 1, MAXPORT,
|
|
|
|
"port number");
|
|
|
|
CHECK("parse_uint(srcport)", result);
|
|
|
|
srcport = num;
|
|
|
|
*hash = '\0';
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-02-05 07:56:05 +11:00
|
|
|
srcport = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 13:34:18 +01:00
|
|
|
if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_sockaddr_fromin6(&srcaddr, &in6, srcport);
|
|
|
|
isc_net_disableipv4();
|
2015-02-05 13:34:18 +01:00
|
|
|
} else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_sockaddr_fromin(&srcaddr, &in4, srcport);
|
|
|
|
isc_net_disableipv6();
|
|
|
|
} else {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (hash != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
*hash = '#';
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("invalid address %s", value);
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (hash != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
*hash = '#';
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
have_src = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
return (value_from_next);
|
|
|
|
case 'c':
|
|
|
|
tr.base = value;
|
|
|
|
tr.length = strlen(value);
|
|
|
|
result = dns_rdataclass_fromtext(&rdclass,
|
|
|
|
(isc_textregion_t *)&tr);
|
|
|
|
CHECK("dns_rdataclass_fromtext", result);
|
|
|
|
query->rdclass = rdclass;
|
|
|
|
return (value_from_next);
|
|
|
|
case 'f':
|
|
|
|
batchname = value;
|
|
|
|
return (value_from_next);
|
|
|
|
case 'p':
|
|
|
|
GLOBAL();
|
|
|
|
result = parse_uint(&num, value, MAXPORT, "port number");
|
|
|
|
CHECK("parse_uint(port)", result);
|
|
|
|
port = num;
|
|
|
|
return (value_from_next);
|
|
|
|
case 't':
|
|
|
|
tr.base = value;
|
|
|
|
tr.length = strlen(value);
|
|
|
|
result = dns_rdatatype_fromtext(&rdtype,
|
|
|
|
(isc_textregion_t *)&tr);
|
|
|
|
CHECK("dns_rdatatype_fromtext", result);
|
|
|
|
query->rdtype = rdtype;
|
|
|
|
return (value_from_next);
|
|
|
|
case 'x':
|
2018-11-02 14:23:01 +00:00
|
|
|
get_reverse(textname, sizeof(textname), value);
|
2017-09-14 18:11:56 +10:00
|
|
|
strlcpy(query->textname, textname, sizeof(query->textname));
|
2015-02-05 07:56:05 +11:00
|
|
|
query->rdtype = dns_rdatatype_ptr;
|
|
|
|
query->rdclass = dns_rdataclass_in;
|
2018-04-17 08:29:14 -07:00
|
|
|
*setname = true;
|
2015-02-05 07:56:05 +11:00
|
|
|
return (value_from_next);
|
|
|
|
global_option:
|
|
|
|
fprintf(stderr, "Ignored late global option: -%s\n", option);
|
|
|
|
usage();
|
|
|
|
default:
|
|
|
|
invalid_option:
|
|
|
|
fprintf(stderr, "Invalid option: -%s\n", option);
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct query *
|
2018-08-07 16:46:53 +02:00
|
|
|
clone_default_query(void) {
|
2015-02-05 07:56:05 +11:00
|
|
|
struct query *query;
|
|
|
|
|
|
|
|
query = isc_mem_allocate(mctx, sizeof(struct query));
|
|
|
|
memmove(query, &default_query, sizeof(struct query));
|
|
|
|
if (default_query.ecs_addr != NULL) {
|
|
|
|
size_t len = sizeof(isc_sockaddr_t);
|
|
|
|
|
|
|
|
query->ecs_addr = isc_mem_allocate(mctx, len);
|
|
|
|
memmove(query->ecs_addr, default_query.ecs_addr, len);
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->timeout == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query->timeout = tcp_mode ? TCPTIMEOUT : UDPTIMEOUT;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
return (query);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
2017-01-24 17:48:31 +11:00
|
|
|
/*%
|
|
|
|
* Because we may be trying to do memory allocation recording, we're going
|
|
|
|
* to need to parse the arguments for the -m *before* we start the main
|
|
|
|
* argument parsing routine.
|
|
|
|
*
|
|
|
|
* I'd prefer not to have to do this, but I am not quite sure how else to
|
|
|
|
* fix the problem. Argument parsing in mdig involves memory allocation
|
|
|
|
* by its nature, so it can't be done in the main argument parser.
|
|
|
|
*/
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
preparse_args(int argc, char **argv) {
|
|
|
|
int rc;
|
2017-01-24 17:48:31 +11:00
|
|
|
char **rv;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *option;
|
|
|
|
bool ipv4only = false, ipv6only = false;
|
2017-01-24 17:48:31 +11:00
|
|
|
|
|
|
|
rc = argc;
|
|
|
|
rv = argv;
|
|
|
|
for (rc--, rv++; rc > 0; rc--, rv++) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (rv[0][0] != '-') {
|
2017-01-24 17:48:31 +11:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-01-24 17:48:31 +11:00
|
|
|
option = &rv[0][1];
|
|
|
|
while (strpbrk(option, single_dash_opts) == &option[0]) {
|
|
|
|
switch (option[0]) {
|
|
|
|
case 'm':
|
|
|
|
isc_mem_debugging = ISC_MEM_DEBUGTRACE |
|
2020-02-12 13:59:18 +01:00
|
|
|
ISC_MEM_DEBUGRECORD;
|
2017-01-24 17:48:31 +11:00
|
|
|
break;
|
2017-08-16 11:10:24 +02:00
|
|
|
case '4':
|
|
|
|
if (ipv6only) {
|
|
|
|
fatal("only one of -4 and -6 allowed");
|
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
ipv4only = true;
|
2017-08-16 11:10:24 +02:00
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
if (ipv4only) {
|
|
|
|
fatal("only one of -4 and -6 allowed");
|
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
ipv6only = true;
|
2017-08-16 11:10:24 +02:00
|
|
|
break;
|
2017-01-24 17:48:31 +11:00
|
|
|
}
|
|
|
|
option = &option[1];
|
|
|
|
}
|
2018-11-06 11:59:04 +11:00
|
|
|
if (strlen(option) == 0U) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Look for dash value option. */
|
|
|
|
if (strpbrk(option, dash_opts) != &option[0] ||
|
|
|
|
strlen(option) > 1U) {
|
|
|
|
/* Error or value in option. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Dash value is next argument so we need to skip it. */
|
|
|
|
rc--, rv++;
|
|
|
|
/* Handle missing argument */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (rc == 0) {
|
2018-11-06 11:59:04 +11:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-01-24 17:48:31 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
parse_args(bool is_batchfile, int argc, char **argv) {
|
2015-02-05 07:56:05 +11:00
|
|
|
struct query *query = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
char batchline[MXNAME];
|
|
|
|
int bargc;
|
|
|
|
char *bargv[64];
|
|
|
|
int rc;
|
|
|
|
char **rv;
|
|
|
|
bool global = true;
|
|
|
|
char *last;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The semantics for parsing the args is a bit complex; if
|
|
|
|
* we don't have a host yet, make the arg apply globally,
|
|
|
|
* otherwise make it apply to the latest host. This is
|
|
|
|
* a bit different than the previous versions, but should
|
|
|
|
* form a consistent user interface.
|
|
|
|
*
|
|
|
|
* First, create a "default query" which won't actually be used
|
|
|
|
* anywhere, except for cloning into new queries
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!is_batchfile) {
|
|
|
|
default_query.textname[0] = 0;
|
2018-04-17 08:29:14 -07:00
|
|
|
default_query.recurse = true;
|
|
|
|
default_query.have_aaonly = false;
|
|
|
|
default_query.have_adflag = true; /*XXX*/
|
|
|
|
default_query.have_cdflag = false;
|
|
|
|
default_query.have_zflag = false;
|
|
|
|
default_query.dnssec = false;
|
|
|
|
default_query.expire = false;
|
|
|
|
default_query.send_cookie = false;
|
2015-07-06 09:44:24 +10:00
|
|
|
default_query.cookie = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
default_query.nsid = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
default_query.rdtype = dns_rdatatype_a;
|
|
|
|
default_query.rdclass = dns_rdataclass_in;
|
|
|
|
default_query.udpsize = 0;
|
|
|
|
default_query.edns = 0; /*XXX*/
|
|
|
|
default_query.ednsopts = NULL;
|
|
|
|
default_query.ednsoptscnt = 0;
|
|
|
|
default_query.ednsflags = 0;
|
|
|
|
default_query.ecs_addr = NULL;
|
|
|
|
default_query.timeout = 0;
|
|
|
|
default_query.udptimeout = 0;
|
|
|
|
default_query.udpretries = 3;
|
|
|
|
ISC_LINK_INIT(&default_query, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_batchfile) {
|
|
|
|
/* Processing '-f batchfile'. */
|
|
|
|
query = clone_default_query();
|
2018-04-17 08:29:14 -07:00
|
|
|
global = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-02-05 07:56:05 +11:00
|
|
|
query = &default_query;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
rc = argc;
|
|
|
|
rv = argv;
|
|
|
|
for (rc--, rv++; rc > 0; rc--, rv++) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strncmp(rv[0], "%", 1) == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
if (rv[0][0] == '@') {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (server != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("server already set to @%s", server);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
server = &rv[0][1];
|
|
|
|
} else if (rv[0][0] == '+') {
|
|
|
|
plus_option(&rv[0][1], query, global);
|
|
|
|
} else if (rv[0][0] == '-') {
|
2018-04-17 08:29:14 -07:00
|
|
|
bool setname = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
if (rc <= 1) {
|
2020-02-12 13:59:18 +01:00
|
|
|
if (dash_option(&rv[0][1], NULL, query, global,
|
|
|
|
&setname)) {
|
2015-02-05 07:56:05 +11:00
|
|
|
rc--;
|
|
|
|
rv++;
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
if (dash_option(&rv[0][1], rv[1], query, global,
|
|
|
|
&setname)) {
|
2015-02-05 07:56:05 +11:00
|
|
|
rc--;
|
|
|
|
rv++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (setname) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query == &default_query) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query = clone_default_query();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
ISC_LIST_APPEND(queries, query, link);
|
|
|
|
|
|
|
|
default_query.textname[0] = 0;
|
|
|
|
query = clone_default_query();
|
2018-04-17 08:29:14 -07:00
|
|
|
global = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Anything which isn't an option
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query == &default_query) {
|
2015-02-05 07:56:05 +11:00
|
|
|
query = clone_default_query();
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-09-14 18:11:56 +10:00
|
|
|
strlcpy(query->textname, rv[0],
|
2015-02-05 07:56:05 +11:00
|
|
|
sizeof(query->textname));
|
|
|
|
ISC_LIST_APPEND(queries, query, link);
|
|
|
|
|
|
|
|
query = clone_default_query();
|
2018-04-17 08:29:14 -07:00
|
|
|
global = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
/* XXX Error message */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a batchfile, read the query list from it.
|
|
|
|
*/
|
|
|
|
if ((batchname != NULL) && !is_batchfile) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strcmp(batchname, "-") == 0) {
|
2015-02-05 07:56:05 +11:00
|
|
|
batchfp = stdin;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-02-05 07:56:05 +11:00
|
|
|
batchfp = fopen(batchname, "r");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
if (batchfp == NULL) {
|
|
|
|
perror(batchname);
|
|
|
|
fatal("couldn't open batch file '%s'", batchname);
|
|
|
|
}
|
|
|
|
while (fgets(batchline, sizeof(batchline), batchfp) != 0) {
|
2020-02-12 13:59:18 +01:00
|
|
|
if (batchline[0] == '\r' || batchline[0] == '\n' ||
|
2020-02-13 14:44:37 -08:00
|
|
|
batchline[0] == '#' || batchline[0] == ';')
|
|
|
|
{
|
2015-02-19 15:53:20 +11:00
|
|
|
continue;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
for (bargc = 1, bargv[bargc] = strtok_r(
|
|
|
|
batchline, " \t\r\n", &last);
|
|
|
|
(bargc < 14) && bargv[bargc]; bargc++,
|
2020-02-13 14:44:37 -08:00
|
|
|
bargv[bargc] = strtok_r(NULL, " \t\r\n", &last))
|
|
|
|
{
|
2018-03-21 21:08:29 +00:00
|
|
|
/* empty body */
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
bargv[0] = argv[0];
|
2018-04-17 08:29:14 -07:00
|
|
|
parse_args(true, bargc, (char **)bargv);
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (batchfp != stdin) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fclose(batchfp);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
|
|
|
if (query != &default_query) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (query->ecs_addr != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_mem_free(mctx, query->ecs_addr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_mem_free(mctx, query);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*% Main processing routine for mdig */
|
|
|
|
int
|
2020-02-13 14:44:37 -08:00
|
|
|
main(int argc, char *argv[]) {
|
2021-05-19 17:18:22 -07:00
|
|
|
struct query *query = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
|
|
|
isc_sockaddr_t bind_any;
|
2021-05-19 17:18:22 -07:00
|
|
|
isc_log_t *lctx = NULL;
|
|
|
|
isc_logconfig_t *lcfg = NULL;
|
Refactor taskmgr to run on top of netmgr
This commit changes the taskmgr to run the individual tasks on the
netmgr internal workers. While an effort has been put into keeping the
taskmgr interface intact, couple of changes have been made:
* The taskmgr has no concept of universal privileged mode - rather the
tasks are either privileged or unprivileged (normal). The privileged
tasks are run as a first thing when the netmgr is unpaused. There
are now four different queues in in the netmgr:
1. priority queue - netievent on the priority queue are run even when
the taskmgr enter exclusive mode and netmgr is paused. This is
needed to properly start listening on the interfaces, free
resources and resume.
2. privileged task queue - only privileged tasks are queued here and
this is the first queue that gets processed when network manager
is unpaused using isc_nm_resume(). All netmgr workers need to
clean the privileged task queue before they all proceed normal
operation. Both task queues are processed when the workers are
finished.
3. task queue - only (traditional) task are scheduled here and this
queue along with privileged task queues are process when the
netmgr workers are finishing. This is needed to process the task
shutdown events.
4. normal queue - this is the queue with netmgr events, e.g. reading,
sending, callbacks and pretty much everything is processed here.
* The isc_taskmgr_create() now requires initialized netmgr (isc_nm_t)
object.
* The isc_nm_destroy() function now waits for indefinite time, but it
will print out the active objects when in tracing mode
(-DNETMGR_TRACE=1 and -DNETMGR_TRACE_VERBOSE=1), the netmgr has been
made a little bit more asynchronous and it might take longer time to
shutdown all the active networking connections.
* Previously, the isc_nm_stoplistening() was a synchronous operation.
This has been changed and the isc_nm_stoplistening() just schedules
the child sockets to stop listening and exits. This was needed to
prevent a deadlock as the the (traditional) tasks are now executed on
the netmgr threads.
* The socket selection logic in isc__nm_udp_send() was flawed, but
fortunatelly, it was broken, so we never hit the problem where we
created uvreq_t on a socket from nmhandle_t, but then a different
socket could be picked up and then we were trying to run the send
callback on a socket that had different threadid than currently
running.
2021-04-09 11:31:19 +02:00
|
|
|
isc_nm_t *netmgr = NULL;
|
|
|
|
isc_taskmgr_t *taskmgr = NULL;
|
2021-04-27 00:07:43 +02:00
|
|
|
isc_task_t *task = NULL;
|
|
|
|
dns_dispatchmgr_t *dispatchmgr = NULL;
|
2021-05-19 17:18:22 -07:00
|
|
|
dns_dispatch_t *dispatchvx = NULL;
|
|
|
|
dns_view_t *view = NULL;
|
Dispatch API simplification
- Many dispatch attributes can be set implicitly instead of being passed
in. we can infer whether to set DNS_DISPATCHATTR_TCP or _UDP from
whether we're calling dns_dispatch_createtcp() or _createudp(). we
can also infer DNS_DISPATCHATTR_IPV4 or _IPV6 from the addresses or
the socket that were passed in.
- We no longer use dup'd sockets in UDP dispatches, so the 'dup_socket'
parameter has been removed from dns_dispatch_createudp(), along with
the code implementing it. also removed isc_socket_dup() since it no
longer has any callers.
- The 'buffersize' parameter was ignored and has now been removed;
buffersize is now fixed at 4096.
- Maxbuffers and maxrequests don't need to be passed in on every call to
dns_dispatch_createtcp() and _createudp().
In all current uses, the value for mgr->maxbuffers will either be
raised once from its default of 20000 to 32768, or else left
alone. (passing in a value lower than 20000 does not lower it.) there
isn't enough difference between these values for there to be any need
to configure this.
The value for disp->maxrequests controls both the quota of concurrent
requests for a dispatch and also the size of the dispatch socket
memory pool. it's not clear that this quota is necessary at all. the
memory pool size currently starts at 32768, but is sometimes lowered
to 4096, which is definitely unnecessary.
This commit sets both values permanently to 32768.
- Previously TCP dispatches allocated their own separate QID table,
which didn't incorporate a port table. this commit removes
per-dispatch QID tables and shares the same table between all
dispatches. since dispatches are created for each TCP socket, this may
speed up the dispatch allocation process. there may be a slight
increase in lock contention since all dispatches are sharing a single
QID table, but since TCP sockets are used less often than UDP
sockets (which were already sharing a QID table), it should not be a
substantial change.
- The dispatch port table was being used to determine whether a port was
already in use; if so, then a UDP socket would be bound with
REUSEADDR. this commit removes the port table, and always binds UDP
sockets that way.
2020-12-17 00:43:00 -08:00
|
|
|
unsigned int i;
|
2020-02-13 14:44:37 -08:00
|
|
|
int ns;
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
RUNCHECK(isc_app_start());
|
|
|
|
|
|
|
|
dns_result_register();
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (isc_net_probeipv4() == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv4 = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (isc_net_probeipv6() == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv6 = true;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!have_ipv4 && !have_ipv6) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("could not find either IPv4 or IPv6");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2017-01-24 17:48:31 +11:00
|
|
|
preparse_args(argc, argv);
|
|
|
|
|
2019-09-05 18:40:57 +02:00
|
|
|
isc_mem_create(&mctx);
|
2020-03-18 14:17:55 +11:00
|
|
|
isc_log_create(mctx, &lctx, &lcfg);
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2018-04-22 14:56:28 +02:00
|
|
|
RUNCHECK(dst_lib_init(mctx, NULL));
|
2018-05-28 15:22:23 +02:00
|
|
|
isc_nonce_buf(cookie_secret, sizeof(cookie_secret));
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
ISC_LIST_INIT(queries);
|
2018-04-17 08:29:14 -07:00
|
|
|
parse_args(false, argc, argv);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (server == NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("a server '@xxx' is required");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
ns = 0;
|
2017-08-16 11:10:24 +02:00
|
|
|
result = bind9_getaddresses(server, port, &dstaddr, 1, &ns);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
fatal("couldn't get address for '%s': %s", server,
|
|
|
|
isc_result_totext(result));
|
2017-08-16 11:10:24 +02:00
|
|
|
}
|
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
if (isc_sockaddr_pf(&dstaddr) == PF_INET && have_ipv6) {
|
|
|
|
isc_net_disableipv6();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv6 = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
} else if (isc_sockaddr_pf(&dstaddr) == PF_INET6 && have_ipv4) {
|
|
|
|
isc_net_disableipv4();
|
2018-04-17 08:29:14 -07:00
|
|
|
have_ipv4 = false;
|
2015-02-05 07:56:05 +11:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (have_ipv4 && have_ipv6) {
|
2015-02-05 07:56:05 +11:00
|
|
|
fatal("can't choose between IPv4 and IPv6");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
|
2021-01-14 13:02:57 -08:00
|
|
|
isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL);
|
2015-02-05 07:56:05 +11:00
|
|
|
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
2021-01-14 13:02:57 -08:00
|
|
|
RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
if (have_ipv4) {
|
|
|
|
isc_sockaddr_any(&bind_any);
|
|
|
|
} else {
|
|
|
|
isc_sockaddr_any6(&bind_any);
|
|
|
|
}
|
2021-01-14 13:02:57 -08:00
|
|
|
RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr,
|
Dispatch API simplification
- Many dispatch attributes can be set implicitly instead of being passed
in. we can infer whether to set DNS_DISPATCHATTR_TCP or _UDP from
whether we're calling dns_dispatch_createtcp() or _createudp(). we
can also infer DNS_DISPATCHATTR_IPV4 or _IPV6 from the addresses or
the socket that were passed in.
- We no longer use dup'd sockets in UDP dispatches, so the 'dup_socket'
parameter has been removed from dns_dispatch_createudp(), along with
the code implementing it. also removed isc_socket_dup() since it no
longer has any callers.
- The 'buffersize' parameter was ignored and has now been removed;
buffersize is now fixed at 4096.
- Maxbuffers and maxrequests don't need to be passed in on every call to
dns_dispatch_createtcp() and _createudp().
In all current uses, the value for mgr->maxbuffers will either be
raised once from its default of 20000 to 32768, or else left
alone. (passing in a value lower than 20000 does not lower it.) there
isn't enough difference between these values for there to be any need
to configure this.
The value for disp->maxrequests controls both the quota of concurrent
requests for a dispatch and also the size of the dispatch socket
memory pool. it's not clear that this quota is necessary at all. the
memory pool size currently starts at 32768, but is sometimes lowered
to 4096, which is definitely unnecessary.
This commit sets both values permanently to 32768.
- Previously TCP dispatches allocated their own separate QID table,
which didn't incorporate a port table. this commit removes
per-dispatch QID tables and shares the same table between all
dispatches. since dispatches are created for each TCP socket, this may
speed up the dispatch allocation process. there may be a slight
increase in lock contention since all dispatches are sharing a single
QID table, but since TCP sockets are used less often than UDP
sockets (which were already sharing a QID table), it should not be a
substantial change.
- The dispatch port table was being used to determine whether a port was
already in use; if so, then a UDP socket would be bound with
REUSEADDR. this commit removes the port table, and always binds UDP
sockets that way.
2020-12-17 00:43:00 -08:00
|
|
|
have_src ? &srcaddr : &bind_any, 0,
|
|
|
|
&dispatchvx));
|
2020-12-16 01:32:06 -08:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
RUNCHECK(dns_requestmgr_create(
|
2021-01-14 13:02:57 -08:00
|
|
|
mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
|
|
|
|
have_ipv6 ? dispatchvx : NULL, &requestmgr));
|
2015-02-05 07:56:05 +11:00
|
|
|
|
|
|
|
RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
|
|
|
|
|
|
|
|
query = ISC_LIST_HEAD(queries);
|
|
|
|
RUNCHECK(isc_app_onrun(mctx, task, sendqueries, query));
|
|
|
|
|
2020-09-16 12:40:52 +10:00
|
|
|
/*
|
|
|
|
* Stall to the start of a new second.
|
|
|
|
*/
|
|
|
|
if (burst) {
|
|
|
|
isc_time_t start, now;
|
|
|
|
RUNCHECK(isc_time_now(&start));
|
|
|
|
/*
|
|
|
|
* Sleep to 1ms of the end of the second then run a busy loop
|
|
|
|
* until the second changes.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
RUNCHECK(isc_time_now(&now));
|
|
|
|
if (isc_time_seconds(&start) == isc_time_seconds(&now))
|
|
|
|
{
|
|
|
|
int us = US_PER_SEC -
|
|
|
|
(isc_time_nanoseconds(&now) /
|
|
|
|
NS_PER_US);
|
|
|
|
if (us > US_PER_MS) {
|
|
|
|
usleep(us - US_PER_MS);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
}
|
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
(void)isc_app_run();
|
|
|
|
|
2021-03-04 17:22:01 +11:00
|
|
|
dns_view_detach(&view);
|
|
|
|
|
|
|
|
dns_requestmgr_shutdown(requestmgr);
|
|
|
|
dns_requestmgr_detach(&requestmgr);
|
|
|
|
|
|
|
|
dns_dispatch_detach(&dispatchvx);
|
|
|
|
dns_dispatchmgr_destroy(&dispatchmgr);
|
|
|
|
|
|
|
|
isc_task_shutdown(task);
|
|
|
|
isc_task_detach(&task);
|
2021-04-27 00:07:43 +02:00
|
|
|
|
2021-01-14 13:02:57 -08:00
|
|
|
isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL);
|
2021-03-04 17:22:01 +11:00
|
|
|
|
|
|
|
dst_lib_destroy();
|
|
|
|
|
|
|
|
isc_log_destroy(&lctx);
|
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
query = ISC_LIST_HEAD(queries);
|
|
|
|
while (query != NULL) {
|
|
|
|
struct query *next = ISC_LIST_NEXT(query, link);
|
|
|
|
|
2018-07-12 12:38:24 +10:00
|
|
|
if (query->ednsopts != NULL) {
|
|
|
|
for (i = 0; i < EDNSOPTS; i++) {
|
|
|
|
if (query->ednsopts[i].value != NULL) {
|
|
|
|
isc_mem_free(mctx,
|
|
|
|
query->ednsopts[i].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isc_mem_free(mctx, query->ednsopts);
|
|
|
|
}
|
2016-01-29 17:41:29 -08:00
|
|
|
if (query->ecs_addr != NULL) {
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_mem_free(mctx, query->ecs_addr);
|
2016-01-29 17:41:29 -08:00
|
|
|
query->ecs_addr = NULL;
|
|
|
|
}
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_mem_free(mctx, query);
|
|
|
|
query = next;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (default_query.ecs_addr != NULL) {
|
2016-01-29 17:41:29 -08:00
|
|
|
isc_mem_free(mctx, default_query.ecs_addr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-01-29 17:41:29 -08:00
|
|
|
|
2015-02-05 07:56:05 +11:00
|
|
|
isc_mem_destroy(&mctx);
|
|
|
|
|
|
|
|
isc_app_finish();
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|