You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.5 KiB
221 lines
6.5 KiB
/* host.c - DNS lookup utility
|
|
*
|
|
* Copyright 2014 Rich Felker <dalias@aerifal.cx>
|
|
*
|
|
* No standard, but there's a version in bind9
|
|
|
|
USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
|
|
|
|
config HOST
|
|
bool "host"
|
|
default n
|
|
help
|
|
usage: host [-av] [-t TYPE] NAME [SERVER]
|
|
|
|
Perform DNS lookup on NAME, which can be a domain name to lookup,
|
|
or an IPv4 dotted or IPv6 colon-separated address to reverse lookup.
|
|
SERVER (if present) is the DNS server to use.
|
|
|
|
-a -v -t ANY
|
|
-t TYPE query records of type TYPE
|
|
-v verbose
|
|
*/
|
|
|
|
#define FOR_host
|
|
#include "toys.h"
|
|
|
|
GLOBALS(
|
|
char *type_str;
|
|
)
|
|
|
|
#include <resolv.h>
|
|
|
|
#define PL_IP 1
|
|
#define PL_NAME 2
|
|
#define PL_DATA 3
|
|
#define PL_TEXT 4
|
|
#define PL_SOA 5
|
|
#define PL_MX 6
|
|
#define PL_SRV 7
|
|
|
|
static const struct rrt {
|
|
const char *name;
|
|
const char *msg;
|
|
int pl;
|
|
int af;
|
|
} rrt[] = {
|
|
[1] = { "A", "has address", PL_IP, AF_INET },
|
|
[28] = { "AAAA", "has address", PL_IP, AF_INET6 },
|
|
[2] = { "NS", "name server", PL_NAME },
|
|
[5] = { "CNAME", "is a nickname for", PL_NAME },
|
|
[16] = { "TXT", "descriptive text", PL_TEXT },
|
|
[6] = { "SOA", "start of authority", PL_SOA },
|
|
[12] = { "PTR", "domain name pointer", PL_NAME },
|
|
[15] = { "MX", "mail is handled", PL_MX },
|
|
[33] = { "SRV", "mail is handled", PL_SRV },
|
|
[255] = { "*", 0, 0 },
|
|
};
|
|
|
|
static const char rct[16][32] = {
|
|
"Success",
|
|
"Format error",
|
|
"Server failure",
|
|
"Non-existant domain",
|
|
"Not implemented",
|
|
"Refused",
|
|
};
|
|
|
|
void host_main(void)
|
|
{
|
|
int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type,
|
|
i, j, ret, sec, count, rcode, qlen, alen, pllen = 0,
|
|
abuf_len = 65536; // Largest TCP response.
|
|
unsigned ttl, pri, v[5];
|
|
unsigned char *abuf = xmalloc(abuf_len);
|
|
char *rrname = xmalloc(MAXDNAME);
|
|
unsigned char qbuf[280], *p;
|
|
char *name, *nsname, plname[640], ptrbuf[128];
|
|
struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST };
|
|
|
|
name = *toys.optargs;
|
|
nsname = toys.optargs[1];
|
|
|
|
if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255";
|
|
if (!getaddrinfo(name, 0, &iplit_hints, &ai)) {
|
|
unsigned char *a;
|
|
static const char xdigits[] = "0123456789abcdef";
|
|
|
|
if (ai->ai_family == AF_INET) {
|
|
a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
|
snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa",
|
|
a[3], a[2], a[1], a[0]);
|
|
} else if (ai->ai_family == AF_INET6) {
|
|
a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
|
for (j=0, i=15; i>=0; i--) {
|
|
ptrbuf[j++] = xdigits[a[i]&15];
|
|
ptrbuf[j++] = '.';
|
|
ptrbuf[j++] = xdigits[a[i]>>4];
|
|
ptrbuf[j++] = '.';
|
|
}
|
|
strcpy(ptrbuf+j, "ip6.arpa");
|
|
}
|
|
name = ptrbuf;
|
|
if (!TT.type_str) TT.type_str="12";
|
|
} else if (!TT.type_str) TT.type_str="1";
|
|
|
|
if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str);
|
|
else {
|
|
type = -1;
|
|
for (i=0; i<ARRAY_LEN(rrt); i++) {
|
|
if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) {
|
|
type = i;
|
|
break;
|
|
}
|
|
}
|
|
if (!strcasecmp(TT.type_str, "any")) type = 255;
|
|
if (type < 0) error_exit("Invalid query type: %s", TT.type_str);
|
|
}
|
|
|
|
qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof(qbuf));
|
|
if (qlen < 0) error_exit("Invalid query parameters: %s", name);
|
|
|
|
if (nsname) {
|
|
struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM };
|
|
|
|
if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0)
|
|
error_exit("Error looking up server name: %s", gai_strerror(ret));
|
|
int s = xsocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
|
xconnect(s, ai->ai_addr, ai->ai_addrlen);
|
|
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 },
|
|
sizeof(struct timeval));
|
|
printf("Using domain server %s:\n", nsname);
|
|
send(s, qbuf, qlen, 0);
|
|
alen = recv(s, abuf, abuf_len, 0);
|
|
} else alen = res_send(qbuf, qlen, abuf, abuf_len);
|
|
|
|
if (alen < 12) error_exit("Host not found.");
|
|
|
|
rcode = abuf[3] & 15;
|
|
|
|
if (verbose) {
|
|
printf("rcode = %d (%s), ancount = %d\n",
|
|
rcode, rct[rcode], 256*abuf[6] + abuf[7]);
|
|
if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n");
|
|
}
|
|
|
|
if (rcode) error_exit("Host not found.");
|
|
|
|
p = abuf + 12;
|
|
for (sec=0; sec<4; sec++) {
|
|
count = 256*abuf[4+2*sec] + abuf[5+2*sec];
|
|
if (verbose && count>0 && sec>1)
|
|
puts(sec==2 ? "For authoritative answers, see:"
|
|
: "Additional information:");
|
|
|
|
for (; count--; p += pllen) {
|
|
p += dn_expand(abuf, abuf+alen, p, rrname, MAXDNAME);
|
|
type = (p[0]<<8) + p[1];
|
|
p += 4;
|
|
if (!sec) continue;
|
|
ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
|
|
p += 4;
|
|
pllen = (p[0]<<8) + p[1];
|
|
p += 2;
|
|
|
|
switch (type<ARRAY_LEN(rrt) ? rrt[type].pl : 0) {
|
|
case PL_IP:
|
|
inet_ntop(rrt[type].af, p, plname, sizeof(plname));
|
|
break;
|
|
case PL_NAME:
|
|
dn_expand(abuf, abuf+alen, p, plname, sizeof(plname));
|
|
break;
|
|
case PL_TEXT:
|
|
snprintf(plname, sizeof(plname), "\"%.*s\"", pllen, p);
|
|
break;
|
|
case PL_SOA:
|
|
i = dn_expand(abuf, abuf+alen, p, plname, sizeof(plname) - 1);
|
|
strcat(plname, " ");
|
|
i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname),
|
|
sizeof(plname)-strlen(plname));
|
|
for (j=0; j<5; j++)
|
|
v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j];
|
|
snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname),
|
|
"(\n\t\t%u\t;serial (version)\n"
|
|
"\t\t%u\t;refresh period\n"
|
|
"\t\t%u\t;retry interval\n"
|
|
"\t\t%u\t;expire time\n"
|
|
"\t\t%u\t;default ttl\n"
|
|
"\t\t)", v[0], v[1], v[2], v[3], v[4]);
|
|
break;
|
|
case PL_MX:
|
|
pri = (p[0]<<8)+p[1];
|
|
snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri);
|
|
dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname),
|
|
sizeof(plname) - strlen(plname));
|
|
break;
|
|
case PL_SRV:
|
|
for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j];
|
|
snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]);
|
|
dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname),
|
|
sizeof(plname) - strlen(plname));
|
|
break;
|
|
default:
|
|
printf("%s unsupported RR type %u\n", rrname, type);
|
|
continue;
|
|
}
|
|
|
|
if (verbose)
|
|
printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname);
|
|
else if (rrt[type].msg)
|
|
printf("%s %s %s\n", rrname, rrt[type].msg, plname);
|
|
}
|
|
if (!verbose && sec==1) break;
|
|
}
|
|
|
|
if (CFG_TOYBOX_FREE) {
|
|
free(abuf);
|
|
free(rrname);
|
|
}
|
|
toys.exitval = rcode;
|
|
}
|