1 /* host.c - DNS lookup utility
3 * Copyright 2014 Rich Felker <dalias@aerifal.cx>
5 * No standard, but there's a version in bind9
7 USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
13 usage: host [-av] [-t TYPE] NAME [SERVER]
15 Perform DNS lookup on NAME, which can be a domain name to lookup,
16 or an ipv4 dotted or ipv6 colon seprated address to reverse lookup.
17 SERVER (if present) is the DNS server to use.
41 static const struct 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 },
59 static const char rct[16][32] = {
63 "Non-existant domain",
70 int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type,
71 i, j, ret, sec, count, rcode, qlen, alen, pllen = 0;
72 unsigned ttl, pri, v[5];
73 unsigned char qbuf[280], abuf[512], *p;
74 char *name, *nsname, rrname[256], plname[640], ptrbuf[64];
75 struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST };
78 nsname = toys.optargs[1];
80 if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255";
81 if (!getaddrinfo(name, 0, &iplit_hints, &ai)) {
83 static const char xdigits[] = "0123456789abcdef";
85 if (ai->ai_family == AF_INET) {
86 a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
87 snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa",
88 a[3], a[2], a[1], a[0]);
89 } else if (ai->ai_family == AF_INET6) {
90 a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
91 for (j=0, i=15; i>=0; i--) {
92 ptrbuf[j++] = xdigits[a[i]&15];
94 ptrbuf[j++] = xdigits[a[i]>>4];
97 strcpy(ptrbuf+j, "ip6.arpa");
100 if (!TT.type_str) TT.type_str="12";
101 } else if (!TT.type_str) TT.type_str="1";
103 if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str);
106 for (i=0; i < sizeof rrt / sizeof *rrt; i++) {
107 if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) {
112 if (!strcasecmp(TT.type_str, "any")) type = 255;
113 if (type < 0) error_exit("Invalid query type: %s", TT.type_str);
116 qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof qbuf);
117 if (qlen < 0) error_exit("Invalid query parameters: %s", name);
120 struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM };
122 if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0)
123 error_exit("Error looking up server name: %s", gai_strerror(ret));
124 int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
125 if (s < 0 || connect(s, ai->ai_addr, ai->ai_addrlen) < 0)
126 perror_exit("Socket error");
127 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 },
128 sizeof(struct timeval));
129 printf("Using domain server %s:\n", nsname);
130 send(s, qbuf, qlen, 0);
131 alen = recv(s, abuf, sizeof abuf, 0);
132 } else alen = res_send(qbuf, qlen, abuf, sizeof abuf);
134 if (alen < 12) error_exit("Host not found.");
136 rcode = abuf[3] & 15;
139 printf("rcode = %d (%s), ancount = %d\n",
140 rcode, rct[rcode], 256*abuf[6] + abuf[7]);
141 if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n");
144 if (rcode) error_exit("Host not found.");
147 for (sec=0; sec<4; sec++) {
148 count = 256*abuf[4+2*sec] + abuf[5+2*sec];
149 if (verbose && count>0 && sec>1)
150 puts(sec==2 ? "For authoritative answers, see:"
151 : "Additional information:");
153 for (; count--; p += pllen) {
154 p += dn_expand(abuf, abuf+alen, p, rrname, sizeof(rrname));
155 type = (p[0]<<8) + p[1];
158 ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
160 pllen = (p[0]<<8) + p[1];
163 switch (type<sizeof(rrt)/sizeof(*rrt) ? rrt[type].pl : 0) {
165 inet_ntop(rrt[type].af, p, plname, sizeof plname);
168 dn_expand(abuf, abuf+alen, p, plname, sizeof plname);
171 snprintf(plname, sizeof plname, "\"%.*s\"", pllen, p);
174 i = dn_expand(abuf, abuf+alen, p, plname, sizeof plname - 1);
176 i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname),
177 sizeof(plname)-strlen(plname));
179 v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j];
180 snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname),
181 "(\n\t\t%u\t;serial (version)\n"
182 "\t\t%u\t;refresh period\n"
183 "\t\t%u\t;retry interval\n"
184 "\t\t%u\t;expire time\n"
185 "\t\t%u\t;default ttl\n"
186 "\t\t)", v[0], v[1], v[2], v[3], v[4]);
189 pri = (p[0]<<8)+p[1];
190 snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri);
191 dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname),
192 sizeof plname - strlen(plname));
195 for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j];
196 snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]);
197 dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname),
198 sizeof plname - strlen(plname));
201 printf("%s unsupported RR type %u\n", rrname, type);
206 printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname);
207 else if (rrt[type].msg)
208 printf("%s %s %s\n", rrname, rrt[type].msg, plname);
210 if (!verbose && sec==1) break;
213 toys.exitval = rcode;