10f66f451Sopenharmony_ci/* host.c - DNS lookup utility 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2014 Rich Felker <dalias@aerifal.cx> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * No standard, but there's a version in bind9 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig HOST 100f66f451Sopenharmony_ci bool "host" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: host [-av] [-t TYPE] NAME [SERVER] 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Perform DNS lookup on NAME, which can be a domain name to lookup, 160f66f451Sopenharmony_ci or an IPv4 dotted or IPv6 colon-separated address to reverse lookup. 170f66f451Sopenharmony_ci SERVER (if present) is the DNS server to use. 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci -a -v -t ANY 200f66f451Sopenharmony_ci -t TYPE query records of type TYPE 210f66f451Sopenharmony_ci -v verbose 220f66f451Sopenharmony_ci*/ 230f66f451Sopenharmony_ci 240f66f451Sopenharmony_ci#define FOR_host 250f66f451Sopenharmony_ci#include "toys.h" 260f66f451Sopenharmony_ci 270f66f451Sopenharmony_ciGLOBALS( 280f66f451Sopenharmony_ci char *type_str; 290f66f451Sopenharmony_ci) 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ci#include <resolv.h> 320f66f451Sopenharmony_ci 330f66f451Sopenharmony_ci#define PL_IP 1 340f66f451Sopenharmony_ci#define PL_NAME 2 350f66f451Sopenharmony_ci#define PL_DATA 3 360f66f451Sopenharmony_ci#define PL_TEXT 4 370f66f451Sopenharmony_ci#define PL_SOA 5 380f66f451Sopenharmony_ci#define PL_MX 6 390f66f451Sopenharmony_ci#define PL_SRV 7 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_cistatic const struct rrt { 420f66f451Sopenharmony_ci const char *name; 430f66f451Sopenharmony_ci const char *msg; 440f66f451Sopenharmony_ci int pl; 450f66f451Sopenharmony_ci int af; 460f66f451Sopenharmony_ci} rrt[] = { 470f66f451Sopenharmony_ci [1] = { "A", "has address", PL_IP, AF_INET }, 480f66f451Sopenharmony_ci [28] = { "AAAA", "has address", PL_IP, AF_INET6 }, 490f66f451Sopenharmony_ci [2] = { "NS", "name server", PL_NAME }, 500f66f451Sopenharmony_ci [5] = { "CNAME", "is a nickname for", PL_NAME }, 510f66f451Sopenharmony_ci [16] = { "TXT", "descriptive text", PL_TEXT }, 520f66f451Sopenharmony_ci [6] = { "SOA", "start of authority", PL_SOA }, 530f66f451Sopenharmony_ci [12] = { "PTR", "domain name pointer", PL_NAME }, 540f66f451Sopenharmony_ci [15] = { "MX", "mail is handled", PL_MX }, 550f66f451Sopenharmony_ci [33] = { "SRV", "mail is handled", PL_SRV }, 560f66f451Sopenharmony_ci [255] = { "*", 0, 0 }, 570f66f451Sopenharmony_ci}; 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_cistatic const char rct[16][32] = { 600f66f451Sopenharmony_ci "Success", 610f66f451Sopenharmony_ci "Format error", 620f66f451Sopenharmony_ci "Server failure", 630f66f451Sopenharmony_ci "Non-existant domain", 640f66f451Sopenharmony_ci "Not implemented", 650f66f451Sopenharmony_ci "Refused", 660f66f451Sopenharmony_ci}; 670f66f451Sopenharmony_ci 680f66f451Sopenharmony_civoid host_main(void) 690f66f451Sopenharmony_ci{ 700f66f451Sopenharmony_ci int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type, 710f66f451Sopenharmony_ci i, j, ret, sec, count, rcode, qlen, alen, pllen = 0, 720f66f451Sopenharmony_ci abuf_len = 65536; // Largest TCP response. 730f66f451Sopenharmony_ci unsigned ttl, pri, v[5]; 740f66f451Sopenharmony_ci unsigned char *abuf = xmalloc(abuf_len); 750f66f451Sopenharmony_ci char *rrname = xmalloc(MAXDNAME); 760f66f451Sopenharmony_ci unsigned char qbuf[280], *p; 770f66f451Sopenharmony_ci char *name, *nsname, plname[640], ptrbuf[128]; 780f66f451Sopenharmony_ci struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST }; 790f66f451Sopenharmony_ci 800f66f451Sopenharmony_ci name = *toys.optargs; 810f66f451Sopenharmony_ci nsname = toys.optargs[1]; 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_ci if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255"; 840f66f451Sopenharmony_ci if (!getaddrinfo(name, 0, &iplit_hints, &ai)) { 850f66f451Sopenharmony_ci unsigned char *a; 860f66f451Sopenharmony_ci static const char xdigits[] = "0123456789abcdef"; 870f66f451Sopenharmony_ci 880f66f451Sopenharmony_ci if (ai->ai_family == AF_INET) { 890f66f451Sopenharmony_ci a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; 900f66f451Sopenharmony_ci snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa", 910f66f451Sopenharmony_ci a[3], a[2], a[1], a[0]); 920f66f451Sopenharmony_ci } else if (ai->ai_family == AF_INET6) { 930f66f451Sopenharmony_ci a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; 940f66f451Sopenharmony_ci for (j=0, i=15; i>=0; i--) { 950f66f451Sopenharmony_ci ptrbuf[j++] = xdigits[a[i]&15]; 960f66f451Sopenharmony_ci ptrbuf[j++] = '.'; 970f66f451Sopenharmony_ci ptrbuf[j++] = xdigits[a[i]>>4]; 980f66f451Sopenharmony_ci ptrbuf[j++] = '.'; 990f66f451Sopenharmony_ci } 1000f66f451Sopenharmony_ci strcpy(ptrbuf+j, "ip6.arpa"); 1010f66f451Sopenharmony_ci } 1020f66f451Sopenharmony_ci name = ptrbuf; 1030f66f451Sopenharmony_ci if (!TT.type_str) TT.type_str="12"; 1040f66f451Sopenharmony_ci } else if (!TT.type_str) TT.type_str="1"; 1050f66f451Sopenharmony_ci 1060f66f451Sopenharmony_ci if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str); 1070f66f451Sopenharmony_ci else { 1080f66f451Sopenharmony_ci type = -1; 1090f66f451Sopenharmony_ci for (i=0; i<ARRAY_LEN(rrt); i++) { 1100f66f451Sopenharmony_ci if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) { 1110f66f451Sopenharmony_ci type = i; 1120f66f451Sopenharmony_ci break; 1130f66f451Sopenharmony_ci } 1140f66f451Sopenharmony_ci } 1150f66f451Sopenharmony_ci if (!strcasecmp(TT.type_str, "any")) type = 255; 1160f66f451Sopenharmony_ci if (type < 0) error_exit("Invalid query type: %s", TT.type_str); 1170f66f451Sopenharmony_ci } 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_ci qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof(qbuf)); 1200f66f451Sopenharmony_ci if (qlen < 0) error_exit("Invalid query parameters: %s", name); 1210f66f451Sopenharmony_ci 1220f66f451Sopenharmony_ci if (nsname) { 1230f66f451Sopenharmony_ci struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM }; 1240f66f451Sopenharmony_ci 1250f66f451Sopenharmony_ci if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0) 1260f66f451Sopenharmony_ci error_exit("Error looking up server name: %s", gai_strerror(ret)); 1270f66f451Sopenharmony_ci int s = xsocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 1280f66f451Sopenharmony_ci xconnect(s, ai->ai_addr, ai->ai_addrlen); 1290f66f451Sopenharmony_ci setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 }, 1300f66f451Sopenharmony_ci sizeof(struct timeval)); 1310f66f451Sopenharmony_ci printf("Using domain server %s:\n", nsname); 1320f66f451Sopenharmony_ci send(s, qbuf, qlen, 0); 1330f66f451Sopenharmony_ci alen = recv(s, abuf, abuf_len, 0); 1340f66f451Sopenharmony_ci } else alen = res_send(qbuf, qlen, abuf, abuf_len); 1350f66f451Sopenharmony_ci 1360f66f451Sopenharmony_ci if (alen < 12) error_exit("Host not found."); 1370f66f451Sopenharmony_ci 1380f66f451Sopenharmony_ci rcode = abuf[3] & 15; 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci if (verbose) { 1410f66f451Sopenharmony_ci printf("rcode = %d (%s), ancount = %d\n", 1420f66f451Sopenharmony_ci rcode, rct[rcode], 256*abuf[6] + abuf[7]); 1430f66f451Sopenharmony_ci if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n"); 1440f66f451Sopenharmony_ci } 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci if (rcode) error_exit("Host not found."); 1470f66f451Sopenharmony_ci 1480f66f451Sopenharmony_ci p = abuf + 12; 1490f66f451Sopenharmony_ci for (sec=0; sec<4; sec++) { 1500f66f451Sopenharmony_ci count = 256*abuf[4+2*sec] + abuf[5+2*sec]; 1510f66f451Sopenharmony_ci if (verbose && count>0 && sec>1) 1520f66f451Sopenharmony_ci puts(sec==2 ? "For authoritative answers, see:" 1530f66f451Sopenharmony_ci : "Additional information:"); 1540f66f451Sopenharmony_ci 1550f66f451Sopenharmony_ci for (; count--; p += pllen) { 1560f66f451Sopenharmony_ci p += dn_expand(abuf, abuf+alen, p, rrname, MAXDNAME); 1570f66f451Sopenharmony_ci type = (p[0]<<8) + p[1]; 1580f66f451Sopenharmony_ci p += 4; 1590f66f451Sopenharmony_ci if (!sec) continue; 1600f66f451Sopenharmony_ci ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; 1610f66f451Sopenharmony_ci p += 4; 1620f66f451Sopenharmony_ci pllen = (p[0]<<8) + p[1]; 1630f66f451Sopenharmony_ci p += 2; 1640f66f451Sopenharmony_ci 1650f66f451Sopenharmony_ci switch (type<ARRAY_LEN(rrt) ? rrt[type].pl : 0) { 1660f66f451Sopenharmony_ci case PL_IP: 1670f66f451Sopenharmony_ci inet_ntop(rrt[type].af, p, plname, sizeof(plname)); 1680f66f451Sopenharmony_ci break; 1690f66f451Sopenharmony_ci case PL_NAME: 1700f66f451Sopenharmony_ci dn_expand(abuf, abuf+alen, p, plname, sizeof(plname)); 1710f66f451Sopenharmony_ci break; 1720f66f451Sopenharmony_ci case PL_TEXT: 1730f66f451Sopenharmony_ci snprintf(plname, sizeof(plname), "\"%.*s\"", pllen, p); 1740f66f451Sopenharmony_ci break; 1750f66f451Sopenharmony_ci case PL_SOA: 1760f66f451Sopenharmony_ci i = dn_expand(abuf, abuf+alen, p, plname, sizeof(plname) - 1); 1770f66f451Sopenharmony_ci strcat(plname, " "); 1780f66f451Sopenharmony_ci i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname), 1790f66f451Sopenharmony_ci sizeof(plname)-strlen(plname)); 1800f66f451Sopenharmony_ci for (j=0; j<5; j++) 1810f66f451Sopenharmony_ci v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j]; 1820f66f451Sopenharmony_ci snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname), 1830f66f451Sopenharmony_ci "(\n\t\t%u\t;serial (version)\n" 1840f66f451Sopenharmony_ci "\t\t%u\t;refresh period\n" 1850f66f451Sopenharmony_ci "\t\t%u\t;retry interval\n" 1860f66f451Sopenharmony_ci "\t\t%u\t;expire time\n" 1870f66f451Sopenharmony_ci "\t\t%u\t;default ttl\n" 1880f66f451Sopenharmony_ci "\t\t)", v[0], v[1], v[2], v[3], v[4]); 1890f66f451Sopenharmony_ci break; 1900f66f451Sopenharmony_ci case PL_MX: 1910f66f451Sopenharmony_ci pri = (p[0]<<8)+p[1]; 1920f66f451Sopenharmony_ci snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri); 1930f66f451Sopenharmony_ci dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname), 1940f66f451Sopenharmony_ci sizeof(plname) - strlen(plname)); 1950f66f451Sopenharmony_ci break; 1960f66f451Sopenharmony_ci case PL_SRV: 1970f66f451Sopenharmony_ci for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j]; 1980f66f451Sopenharmony_ci snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]); 1990f66f451Sopenharmony_ci dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname), 2000f66f451Sopenharmony_ci sizeof(plname) - strlen(plname)); 2010f66f451Sopenharmony_ci break; 2020f66f451Sopenharmony_ci default: 2030f66f451Sopenharmony_ci printf("%s unsupported RR type %u\n", rrname, type); 2040f66f451Sopenharmony_ci continue; 2050f66f451Sopenharmony_ci } 2060f66f451Sopenharmony_ci 2070f66f451Sopenharmony_ci if (verbose) 2080f66f451Sopenharmony_ci printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname); 2090f66f451Sopenharmony_ci else if (rrt[type].msg) 2100f66f451Sopenharmony_ci printf("%s %s %s\n", rrname, rrt[type].msg, plname); 2110f66f451Sopenharmony_ci } 2120f66f451Sopenharmony_ci if (!verbose && sec==1) break; 2130f66f451Sopenharmony_ci } 2140f66f451Sopenharmony_ci 2150f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) { 2160f66f451Sopenharmony_ci free(abuf); 2170f66f451Sopenharmony_ci free(rrname); 2180f66f451Sopenharmony_ci } 2190f66f451Sopenharmony_ci toys.exitval = rcode; 2200f66f451Sopenharmony_ci} 221