From 95578350a3e893519ddd51f24d8bfe617ee651cc Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 26 Dec 2021 08:48:39 -0600 Subject: [PATCH] Clean up host. --- toys/pending/host.c | 271 ++++++++++++++++++-------------------------- 1 file changed, 110 insertions(+), 161 deletions(-) diff --git a/toys/pending/host.c b/toys/pending/host.c index 1610301e..c99eabef 100644 --- a/toys/pending/host.c +++ b/toys/pending/host.c @@ -3,6 +3,8 @@ * Copyright 2014 Rich Felker * * No standard, but there's a version in bind9 + * See https://www.ietf.org/rfc/rfc1035.txt + * See https://www.ietf.org/rfc/rfc3596.txt USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN)) @@ -10,211 +12,158 @@ config HOST bool "host" default n help - usage: host [-av] [-t TYPE] NAME [SERVER] + usage: host [-v] [-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. + Look up DNS records for NAME, either domain name or IPv4/IPv6 address to + reverse lookup, from SERVER or default DNS server(s). - -a -v -t ANY - -t TYPE query records of type TYPE - -v verbose + -a All records + -t TYPE Record TYPE (number or ANY A AAAA CNAME MX NS PTR SOA SRV TXT) + -v Verbose */ #define FOR_host #include "toys.h" +#include GLOBALS( - char *type_str; + char *t; ) -#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 }, + char *name, *msg; + int type; +} rrt[] = { { "A", "has address", 1 }, { "NS", "name server", 2 }, + { "CNAME", "is a nickname for", 5 }, { "SOA", "start of authority", 6 }, + { "PTR", "domain name pointer", 12 }, { "MX", "mail is handled", 15 }, + { "TXT", "descriptive text", 16 }, { "AAAA", "has address", 28 }, + { "SRV", "mail is handled", 33 } }; -static const char rct[16][32] = { - "Success", - "Format error", - "Server failure", - "Non-existant domain", - "Not implemented", - "Refused", -}; +int xdn_expand(char *packet, char *endpkt, char *comp, char *expand, int elen) +{ + int i = dn_expand(packet, endpkt, comp, expand, elen); + + if (i<1) error_exit("bad dn_expand"); + + return i; +} 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"; - + int verbose = FLAG(a)||FLAG(v), type, abuf_len = 65536, //Largest TCP response + i, j, sec, rcode, qlen, alen, pllen = 0, t2len = 2048; + unsigned count, ttl; + char *abuf = xmalloc(abuf_len), *name = *toys.optargs, *p, *ss, + *nsname = toys.optargs[1], *t2 = toybuf+t2len; + struct addrinfo *ai; + + // What kind of query are we doing? + if (!TT.t && FLAG(a)) TT.t = "255"; + if (!getaddrinfo(name, 0,&(struct addrinfo){.ai_flags=AI_NUMERICHOST}, &ai)) { + name = toybuf; 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]); + p = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; + sprintf(name, "%d.%d.%d.%d.in-addr.arpa", p[3], p[2], p[1], p[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"); + p = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; + for (j = 0, i = 15; i>=0; i--) + j += sprintf(name+j, "%x.%x.", p[i]&15, p[i]>>4); + strcpy(name+j, "ip6.arpa"); } - name = ptrbuf; - if (!TT.type_str) TT.type_str="12"; - } else if (!TT.type_str) TT.type_str="1"; + if (!TT.t) TT.t = "12"; + } else if (!TT.t) TT.t = "1"; - if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str); + // Prepare query packet of appropriate type + if (TT.t[0]-'0'<10) type = atoi(TT.t); // TODO + else if (!strcasecmp(TT.t, "any") || strcmp(TT.t, "*")) type = 255; else { - type = -1; - for (i=0; iai_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 }, + ai = xgetaddrinfo(nsname, "53", 0, SOCK_DGRAM, 0, 0); + i = xsocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + xconnect(i, ai->ai_addr, ai->ai_addrlen); + setsockopt(i, 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("Using domain server %s:\n", nsname); + send(i, t2, qlen, 0); + alen = recv(i, abuf, abuf_len, 0); + } else alen = res_send(t2, qlen, abuf, abuf_len); + if (alen < 16) error_exit("Host not found."); + + // Did it error? + rcode = abuf[3]&7; 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"); + printf("rcode = %d, ancount = %d\n", rcode, (int)peek_be(abuf+6, 2)); + if (!(abuf[2]&4)) puts("The following answer is not authoritative:"); } + if (rcode) error_exit("Host not found: %s", + (char *[]){ "Format error", "Server failure", + "Non-existant domain", "Not implemented", "Refused", ""}[rcode-1]); - if (rcode) error_exit("Host not found."); - + // Print the result p = abuf + 12; - for (sec=0; sec<4; sec++) { - count = 256*abuf[4+2*sec] + abuf[5+2*sec]; + for (sec = 0; sec<(2<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 += xdn_expand(abuf, abuf+alen, p, toybuf, 4096-t2len); + if (alen-(p-abuf)<10) error_exit("tilt"); + type = peek_be(p, 2); p += 4; if (!sec) continue; - ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; + ttl = peek_be(p, 4); p += 4; - pllen = (p[0]<<8) + p[1]; + pllen = peek_be(p, 2); p += 2; - - switch (typealen) error_exit("tilt"); + + if (type==1 || type == 28) + inet_ntop(type==1 ? AF_INET : AF_INET6, p, t2, t2len); + else if (type==2 || type==5) xdn_expand(abuf, abuf+alen, p, t2, t2len); + else if (type==16) sprintf(t2, "\"%.*s\"", minof(pllen, t2len), p); + else if (type==6) { + ss = p+xdn_expand(abuf, abuf+alen, p, t2, t2len-1); + j = strlen(t2); + t2[j++] = ' '; + ss += xdn_expand(abuf, abuf+alen, ss, t2+j, t2len-j); + j += strlen(t2+j); + snprintf(t2+j, t2len-j, "(\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)", (unsigned)peek_be(ss, 4), + (unsigned)peek_be(ss+4, 4), (unsigned)peek_be(ss+8, 4), + (unsigned)peek_be(ss+12, 4), (unsigned)peek_be(ss+16, 4)); + } else if (type==15) { + j = peek_be(p, 2); + j = sprintf(t2, verbose ? "%d " : "(pri=%d) by ", j); + xdn_expand(abuf, abuf+alen, p+2, t2+j, t2len-j); + } else if (type==33) { + j = sprintf(t2, "%u %u %u ", (int)peek_be(p, 2), (int)peek_be(p+2, 2), + (int)peek_be(p+4, 2)); + xdn_expand(abuf, abuf+alen, p+6, t2+j, t2len-j); + } else { + printf("%s unsupported RR type %u\n", toybuf, 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); + for (i = 0; rrt[i].type != type; i++); + if (verbose) printf("%s\t%u\tIN %s\t%s\n", toybuf, ttl, rrt[i].name, t2); + else printf("%s %s %s\n", toybuf, rrt[type].msg, t2); } - if (!verbose && sec==1) break; } - if (CFG_TOYBOX_FREE) { - free(abuf); - free(rrname); - } + if (CFG_TOYBOX_FREE) free(abuf); toys.exitval = rcode; } -- 2.39.2