From e266735d08ccf6cac442ac4e6e0defcd05fdea7a Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 8 Jun 2014 15:03:32 -0500 Subject: Add host by Rich Felker. --- toys/pending/host.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 toys/pending/host.c (limited to 'toys/pending/host.c') diff --git a/toys/pending/host.c b/toys/pending/host.c new file mode 100644 index 00000000..4e1a7e7e --- /dev/null +++ b/toys/pending/host.c @@ -0,0 +1,251 @@ +/* host.c - DNS lookup utility + * + * Copyright 2014 Rich Felker + * + * 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 seprated address to reverse lookup. + SERVER (if present) is the DNS server to use. + + -a no idea + -t not a clue + -v verbose +*/ + +#define FOR_host +#include "toys.h" + +GLOBALS( + char *type_str; +) + +#include + +#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; + char *name, *nsname; + int i, j, ret, sec, count, rcode, qlen, alen, pllen = 0, v[5]; + unsigned ttl, pri; + unsigned char qbuf[280], abuf[512], *p; + char rrname[256], plname[640], ptrbuf[64]; + 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)) { + switch (ai->ai_family) { + unsigned char *a; + static const char xdigits[] = "0123456789abcdef"; + case 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]); + break; + case 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"); + break; + } + 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 < sizeof rrt / sizeof *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) { + fprintf(stderr, "Invalid query type: %s\n", TT.type_str); + goto out_error; + } + } + + qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof qbuf); + if (qlen < 0) { + fprintf(stderr, "Invalid query parameters: %s", name); + goto out_error; + } + + if (nsname) { + struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM }; + if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0) { + fprintf(stderr, "Error looking up server name: %s\n", + gai_strerror(ret)); + goto out_error; + } + int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0 || connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { + fprintf(stderr, "Socket error: %s\n", strerror(errno)); + goto out_error; + } + 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, sizeof abuf, 0); + } else { + alen = res_send(qbuf, qlen, abuf, sizeof abuf); + } + + if (alen < 12) { + fprintf(stderr, "Host not found, try again.\n"); + goto out_error; + } + + 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) { + fprintf(stderr, "Host not found.\n"); + if (!verbose) goto out_error; + } + + 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, sizeof rrname); + type = 256*p[0] + p[1]; + p += 4; + if (!sec) continue; + ttl = 16777216*p[0] + 65536*p[1] + 256*p[2] + p[3]; + p += 4; + pllen = 256*p[0] + p[1]; + p += 2; + switch (type