1 /* host.c - DNS lookup utility 2 * 3 * Copyright 2014 Rich Felker <dalias@aerifal.cx> 4 * 5 * No standard, but there's a version in bind9 6 7 USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN)) 8 9 config HOST 10 bool "host" 11 default n 12 help 13 usage: host [-av] [-t TYPE] NAME [SERVER] 14 15 Perform DNS lookup on NAME, which can be a domain name to lookup, 16 or an IPv4 dotted or IPv6 colon-separated address to reverse lookup. 17 SERVER (if present) is the DNS server to use. 18 19 -a -v -t ANY 20 -t TYPE query records of type TYPE 21 -v verbose 22 */ 23 24 #define FOR_host 25 #include "toys.h" 26 27 GLOBALS( 28 char *type_str; 29 ) 30 31 #include <resolv.h> 32 33 #define PL_IP 1 34 #define PL_NAME 2 35 #define PL_DATA 3 36 #define PL_TEXT 4 37 #define PL_SOA 5 38 #define PL_MX 6 39 #define PL_SRV 7 40 41 static const struct rrt { 42 const char *name; 43 const char *msg; 44 int pl; 45 int af; 46 } rrt[] = { 47 [1] = { "A", "has address", PL_IP, AF_INET }, 48 [28] = { "AAAA", "has address", PL_IP, AF_INET6 }, 49 [2] = { "NS", "name server", PL_NAME }, 50 [5] = { "CNAME", "is a nickname for", PL_NAME }, 51 [16] = { "TXT", "descriptive text", PL_TEXT }, 52 [6] = { "SOA", "start of authority", PL_SOA }, 53 [12] = { "PTR", "domain name pointer", PL_NAME }, 54 [15] = { "MX", "mail is handled", PL_MX }, 55 [33] = { "SRV", "mail is handled", PL_SRV }, 56 [255] = { "*", 0, 0 }, 57 }; 58 59 static const char rct[16][32] = { 60 "Success", 61 "Format error", 62 "Server failure", 63 "Non-existant domain", 64 "Not implemented", 65 "Refused", 66 }; 67 68 void host_main(void) 69 { 70 int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type, 71 i, j, ret, sec, count, rcode, qlen, alen, pllen = 0, 72 abuf_len = 65536; // Largest TCP response. 73 unsigned ttl, pri, v[5]; 74 unsigned char *abuf = xmalloc(abuf_len); 75 char *rrname = xmalloc(MAXDNAME); 76 unsigned char qbuf[280], *p; 77 char *name, *nsname, plname[640], ptrbuf[128]; 78 struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST }; 79 80 name = *toys.optargs; 81 nsname = toys.optargs[1]; 82 83 if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255"; 84 if (!getaddrinfo(name, 0, &iplit_hints, &ai)) { 85 unsigned char *a; 86 static const char xdigits[] = "0123456789abcdef"; 87 88 if (ai->ai_family == AF_INET) { 89 a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr; 90 snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa", 91 a[3], a[2], a[1], a[0]); 92 } else if (ai->ai_family == AF_INET6) { 93 a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; 94 for (j=0, i=15; i>=0; i--) { 95 ptrbuf[j++] = xdigits[a[i]&15]; 96 ptrbuf[j++] = '.'; 97 ptrbuf[j++] = xdigits[a[i]>>4]; 98 ptrbuf[j++] = '.'; 99 } 100 strcpy(ptrbuf+j, "ip6.arpa"); 101 } 102 name = ptrbuf; 103 if (!TT.type_str) TT.type_str="12"; 104 } else if (!TT.type_str) TT.type_str="1"; 105 106 if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str); 107 else { 108 type = -1; 109 for (i=0; i<ARRAY_LEN(rrt); i++) { 110 if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) { 111 type = i; 112 break; 113 } 114 } 115 if (!strcasecmp(TT.type_str, "any")) type = 255; 116 if (type < 0) error_exit("Invalid query type: %s", TT.type_str); 117 } 118 119 qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof(qbuf)); 120 if (qlen < 0) error_exit("Invalid query parameters: %s", name); 121 122 if (nsname) { 123 struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM }; 124 125 if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0) 126 error_exit("Error looking up server name: %s", gai_strerror(ret)); 127 int s = xsocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 128 xconnect(s, ai->ai_addr, ai->ai_addrlen); 129 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 }, 130 sizeof(struct timeval)); 131 printf("Using domain server %s:\n", nsname); 132 send(s, qbuf, qlen, 0); 133 alen = recv(s, abuf, abuf_len, 0); 134 } else alen = res_send(qbuf, qlen, abuf, abuf_len); 135 136 if (alen < 12) error_exit("Host not found."); 137 138 rcode = abuf[3] & 15; 139 140 if (verbose) { 141 printf("rcode = %d (%s), ancount = %d\n", 142 rcode, rct[rcode], 256*abuf[6] + abuf[7]); 143 if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n"); 144 } 145 146 if (rcode) error_exit("Host not found."); 147 148 p = abuf + 12; 149 for (sec=0; sec<4; sec++) { 150 count = 256*abuf[4+2*sec] + abuf[5+2*sec]; 151 if (verbose && count>0 && sec>1) 152 puts(sec==2 ? "For authoritative answers, see:" 153 : "Additional information:"); 154 155 for (; count--; p += pllen) { 156 p += dn_expand(abuf, abuf+alen, p, rrname, MAXDNAME); 157 type = (p[0]<<8) + p[1]; 158 p += 4; 159 if (!sec) continue; 160 ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; 161 p += 4; 162 pllen = (p[0]<<8) + p[1]; 163 p += 2; 164 165 switch (type<ARRAY_LEN(rrt) ? rrt[type].pl : 0) { 166 case PL_IP: 167 inet_ntop(rrt[type].af, p, plname, sizeof(plname)); 168 break; 169 case PL_NAME: 170 dn_expand(abuf, abuf+alen, p, plname, sizeof(plname)); 171 break; 172 case PL_TEXT: 173 snprintf(plname, sizeof(plname), "\"%.*s\"", pllen, p); 174 break; 175 case PL_SOA: 176 i = dn_expand(abuf, abuf+alen, p, plname, sizeof(plname) - 1); 177 strcat(plname, " "); 178 i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname), 179 sizeof(plname)-strlen(plname)); 180 for (j=0; j<5; j++) 181 v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j]; 182 snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname), 183 "(\n\t\t%u\t;serial (version)\n" 184 "\t\t%u\t;refresh period\n" 185 "\t\t%u\t;retry interval\n" 186 "\t\t%u\t;expire time\n" 187 "\t\t%u\t;default ttl\n" 188 "\t\t)", v[0], v[1], v[2], v[3], v[4]); 189 break; 190 case PL_MX: 191 pri = (p[0]<<8)+p[1]; 192 snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri); 193 dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname), 194 sizeof(plname) - strlen(plname)); 195 break; 196 case PL_SRV: 197 for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j]; 198 snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]); 199 dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname), 200 sizeof(plname) - strlen(plname)); 201 break; 202 default: 203 printf("%s unsupported RR type %u\n", rrname, type); 204 continue; 205 } 206 207 if (verbose) 208 printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname); 209 else if (rrt[type].msg) 210 printf("%s %s %s\n", rrname, rrt[type].msg, plname); 211 } 212 if (!verbose && sec==1) break; 213 } 214 215 if (CFG_TOYBOX_FREE) { 216 free(abuf); 217 free(rrname); 218 } 219 toys.exitval = rcode; 220 } 221