From b0274663583558f8420215051acb2cca3487fc3b Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Sat, 12 Sep 2020 15:29:02 +0200 Subject: [PATCH] [adig] add '-x' option. (#356) Added a 'dig-style' '-x' option. Also support '-xx' for a IPv6 bit-string PTR query. Fix By: Gisle Vanem (@gvanem) --- src/tools/adig.c | 128 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 9 deletions(-) diff --git a/src/tools/adig.c b/src/tools/adig.c index 998c935f..b577bd79 100644 --- a/src/tools/adig.c +++ b/src/tools/adig.c @@ -171,6 +171,7 @@ static const unsigned char *display_question(const unsigned char *aptr, int alen); static const unsigned char *display_rr(const unsigned char *aptr, const unsigned char *abuf, int alen); +static int convert_query (char **name, int use_bitstring); static const char *type_name(int type); static const char *class_name(int dnsclass); static void usage(void); @@ -184,6 +185,7 @@ int main(int argc, char **argv) ares_channel channel; int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A; int status, nfds, count; + int use_ptr_helper = 0; struct ares_options options; struct hostent *hostent; fd_set read_fds, write_fds; @@ -206,7 +208,7 @@ int main(int argc, char **argv) options.flags = ARES_FLAG_NOCHECKRESP; options.servers = NULL; options.nservers = 0; - while ((c = ares_getopt(argc, argv, "dh?f:s:c:t:T:U:")) != -1) + while ((c = ares_getopt(argc, argv, "dh?f:s:c:t:T:U:x")) != -1) { switch (c) { @@ -329,6 +331,10 @@ int main(int argc, char **argv) options.udp_port = (unsigned short)strtol(optarg, NULL, 0); optmask |= ARES_OPT_UDP_PORT; break; + + case 'x': + use_ptr_helper++; + break; } } argc -= optind; @@ -362,12 +368,15 @@ int main(int argc, char **argv) * otherwise, supply the query name as an argument so we can * distinguish responses for the user when printing them out. */ - if (argc == 1) - ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL); - else + for (i = 1; *argv; i++, argv++) { - for (; *argv; argv++) - ares_query(channel, *argv, dnsclass, type, callback, *argv); + char *query = *argv; + + if (type == T_PTR && dnsclass == C_IN && use_ptr_helper) + if (!convert_query (&query, use_ptr_helper >= 2)) + continue; + + ares_query(channel, query, dnsclass, type, callback, i < argc-1 ? (void*)query : NULL); } /* Wait for all queries to complete. */ @@ -775,6 +784,104 @@ static const unsigned char *display_rr(const unsigned char *aptr, return aptr + dlen; } +/* + * With the '-x' (or '-xx') and '-t PTR' options, convert a query for an + * address into a more useful 'T_PTR' type question. + * Like with an input 'query': + * "a.b.c.d" -> "d.c.b.a".in-addr.arpa" for an IPv4 address. + * "a.b.c....x.y.z" -> "z.y.x....c.d.e.IP6.ARPA" for an IPv6 address. + * + * An example from 'dig -x PTR 2001:470:1:1b9::31': + * + * QUESTION SECTION: + * 1.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.b.1.0.1.0.0.0.0.7.4.0.1.0.0.2.IP6.ARPA. IN PTR + * + * ANSWER SECTION: + * 1.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.b.1.0.1.0.0.0.0.7.4.0.1.0.0.2.IP6.ARPA. 254148 IN PTR ipv6.cybernode.com. + * + * If 'use_bitstring == 1', try to use the more compact RFC-2673 bitstring format. + * Thus the above 'dig' query should become: + * [x13000000000000009b10100007401002].IP6.ARPA. IN PTR + */ +static int convert_query (char **name_p, int use_bitstring) +{ +#ifndef MAX_IP6_RR +#define MAX_IP6_RR (16*sizeof(".x.x") + sizeof(".IP6.ARPA") + 1) +#endif + +#ifdef HAVE_INET_PTON + #define ACCEPTED_RETVAL4 1 + #define ACCEPTED_RETVAL6 1 +#else + #define ACCEPTED_RETVAL4 32 + #define ACCEPTED_RETVAL6 128 +#endif + + static char new_name [MAX_IP6_RR]; + static const char hex_chars[] = "0123456789ABCDEF"; + + union { + struct in_addr addr4; + struct ares_in6_addr addr6; + } addr; + + if (ares_inet_pton (AF_INET, *name_p, &addr.addr4) == 1) + { + unsigned long laddr = ntohl(addr.addr4.s_addr); + unsigned long a1 = (laddr >> 24UL) & 0xFFUL; + unsigned long a2 = (laddr >> 16UL) & 0xFFUL; + unsigned long a3 = (laddr >> 8UL) & 0xFFUL; + unsigned long a4 = laddr & 0xFFUL; + + snprintf(new_name, sizeof(new_name), "%lu.%lu.%lu.%lu.in-addr.arpa", a4, a3, a2, a1); + *name_p = new_name; + return (1); + } + + if (ares_inet_pton(AF_INET6, *name_p, &addr.addr6) == 1) + { + char *c = new_name; + const unsigned char *ip = (const unsigned char*) &addr.addr6; + int max_i = (int)sizeof(addr.addr6) - 1; + int i, hi, lo; + + /* Use the more compact RFC-2673 notation? + * Currently doesn't work or unsupported by the DNS-servers I've tested against. + */ + if (use_bitstring) + { + *c++ = '\\'; + *c++ = '['; + *c++ = 'x'; + for (i = max_i; i >= 0; i--) + { + hi = ip[i] >> 4; + lo = ip[i] & 15; + *c++ = hex_chars [lo]; + *c++ = hex_chars [hi]; + } + strcpy (c, "].IP6.ARPA"); + } + else + { + for (i = max_i; i >= 0; i--) + { + hi = ip[i] >> 4; + lo = ip[i] & 15; + *c++ = hex_chars [lo]; + *c++ = '.'; + *c++ = hex_chars [hi]; + *c++ = '.'; + } + strcpy (c, "IP6.ARPA"); + } + *name_p = new_name; + return (1); + } + printf("Address %s was not legal for this query.\n", *name_p); + return (0); +} + static const char *type_name(int type) { int i; @@ -802,7 +909,7 @@ static const char *class_name(int dnsclass) static void usage(void) { fprintf(stderr, "usage: adig [-h] [-d] [-f flag] [-s server] [-c class] " - "[-t type] [-T|U port] name ...\n"); + "[-t type] [-T|U port] [-x|-xx] name ...\n"); exit(1); } @@ -836,7 +943,7 @@ static void append_addr_list(struct ares_addr_node **head, /* Information from the man page. Formatting taken from man -h */ static void print_help_info_adig(void) { printf("adig, version %s \n\n", ARES_VERSION_STR); - printf("usage: adig [-h] [-d] [-f flag] [-s server] [-c class] [-t type] [-T|U port] name ...\n\n" + printf("usage: adig [-h] [-d] [-f flag] [-s server] [-c class] [-t type] [-T|U port] [-x | -xx] name ...\n\n" " d : Print some extra debugging output.\n" " f : Add a flag. Possible values for flag are igntc, noaliases, norecurse, primary, stayopen, usevc.\n" " h : Display this help and exit.\n\n" @@ -851,6 +958,9 @@ static void print_help_info_adig(void) { " KEY, LOC, MAILA, MAILB, MB, MD,\n" " MF, MG, MINFO, MR, MX, NAPTR, NS,\n" " NSAP, NSAP_PTR, NULL, PTR, PX, RP,\n" - " RT, SIG, SOA, SRV, TXT, WKS, X25\n\n"); + " RT, SIG, SOA, SRV, TXT, WKS, X25\n\n" + " -x : For a '-t PTR a.b.c.d' lookup, query for 'd.c.b.a.in-addr.arpa.'\n" + " -xx : As above, but for IPv6, compact the format into a bitstring like\n" + " '[xabcdef00000000000000000000000000].IP6.ARPA.'\n"); exit(0); }