2 * host.c - Light implementation of the classic host utility
4 * Copyright 2014 Rich Felker
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include <arpa/inet.h>
28 #include <netinet/in.h>
35 #include <sys/socket.h>
45 static const struct rrt
{
51 [1] = { "A", "has address", PL_IP
, AF_INET
},
52 [28] = { "AAAA", "has address", PL_IP
, AF_INET6
},
53 [2] = { "NS", "name server", PL_NAME
},
54 [5] = { "CNAME", "is a nickname for", PL_NAME
},
55 [16] = { "TXT", "descriptive text", PL_TEXT
},
56 [6] = { "SOA", "start of authority", PL_SOA
},
57 [12] = { "PTR", "domain name pointer", PL_NAME
},
58 [15] = { "MX", "mail is handled", PL_MX
},
59 [33] = { "SRV", "mail is handled", PL_SRV
},
60 [255] = { "*", 0, 0 },
63 static const char rct
[16][32] = {
67 "Non-existant domain",
72 int main(int argc
, char **argv
)
75 char *type_str
=0, *name
, *nsname
;
76 int c
, i
, j
, ret
, sec
, count
, rcode
, qlen
, alen
, pllen
= 0;
77 unsigned ttl
, pri
, v
[5];
78 unsigned char qbuf
[280], abuf
[512], *p
;
79 char rrname
[256], plname
[640], ptrbuf
[80];
80 struct addrinfo
*ai
, iplit_hints
= { .ai_flags
= AI_NUMERICHOST
};
82 while ((c
= getopt(argc
, argv
, "avt:")) != EOF
) switch(c
) {
83 case 'a': type_str
="255"; verbose
=1; break;
84 case 'v': verbose
=1; break;
85 case 't': type_str
=optarg
; break;
89 fprintf(stderr
, "Usage: %s [-a] [-v] [-t type] "
90 "hostname [nameserver]\n", argv
[0]);
94 nsname
= argv
[optind
+1];
96 if (!getaddrinfo(name
, 0, &iplit_hints
, &ai
)) {
97 switch (ai
->ai_family
) {
99 static const char xdigits
[] = "0123456789abcdef";
101 a
= (void *)&((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
;
102 snprintf(ptrbuf
, sizeof ptrbuf
,
103 "%d.%d.%d.%d.in-addr.arpa",
104 a
[3], a
[2], a
[1], a
[0]);
107 a
= (void *)&((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
;
108 for (j
=0, i
=15; i
>=0; i
--) {
109 ptrbuf
[j
++] = xdigits
[a
[i
]&15];
111 ptrbuf
[j
++] = xdigits
[a
[i
]>>4];
114 strcpy(ptrbuf
+j
, "ip6.arpa");
118 if (!type_str
) type_str
="12";
120 if (!type_str
) type_str
="1";
123 if (type_str
[0]-'0' < 10u) {
124 type
= atoi(type_str
);
127 for (i
=0; i
< sizeof rrt
/ sizeof *rrt
; i
++) {
128 if (rrt
[i
].name
&& !strcasecmp(type_str
, rrt
[i
].name
)) {
133 if (!strcasecmp(type_str
, "any")) type
= 255;
135 fprintf(stderr
, "Invalid query type: %s\n", type_str
);
140 qlen
= res_mkquery(0, name
, 1, type
, 0, 0, 0, qbuf
, sizeof qbuf
);
142 fprintf(stderr
, "Invalid query parameters: %s", name
);
147 struct addrinfo ns_hints
= { .ai_socktype
= SOCK_DGRAM
};
148 if ((ret
= getaddrinfo(nsname
, "53", &ns_hints
, &ai
)) < 0) {
149 fprintf(stderr
, "Error looking up server name: %s\n",
153 int s
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
154 if (s
< 0 || connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) < 0) {
155 fprintf(stderr
, "Socket error: %s\n", strerror(errno
));
158 setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
,
159 &(struct timeval
){ .tv_sec
= 5 },
160 sizeof (struct timeval
));
161 printf("Using domain server %s:\n", nsname
);
162 send(s
, qbuf
, qlen
, 0);
163 alen
= recv(s
, abuf
, sizeof abuf
, 0);
165 alen
= res_send(qbuf
, qlen
, abuf
, sizeof abuf
);
169 fprintf(stderr
, "Host not found, try again.\n");
173 rcode
= abuf
[3] & 15;
176 printf("rcode = %d (%s), ancount = %d\n",
177 rcode
, rct
[rcode
], 256*abuf
[6] + abuf
[7]);
179 printf("The following answer is not authoritative:\n");
183 fprintf(stderr
, "Host not found.\n");
184 if (!verbose
) return 1;
188 for (sec
=0; sec
<4; sec
++) {
189 count
= 256*abuf
[4+2*sec
] + abuf
[5+2*sec
];
190 if (verbose
&& count
>0 && sec
>1) {
191 puts(sec
==2 ? "For authoritative answers, see:"
192 : "Additional information:");
194 for (; count
--; p
+= pllen
) {
195 p
+= dn_expand(abuf
, abuf
+alen
, p
, rrname
, sizeof rrname
);
196 type
= 256*p
[0] + p
[1];
199 ttl
= 16777216*p
[0] + 65536*p
[1] + 256*p
[2] + p
[3];
201 pllen
= 256*p
[0] + p
[1];
203 switch (type
<sizeof rrt
/sizeof *rrt
? rrt
[type
].pl
: 0) {
205 inet_ntop(rrt
[type
].af
, p
, plname
, sizeof plname
);
208 dn_expand(abuf
, abuf
+alen
, p
, plname
, sizeof plname
);
211 snprintf(plname
, sizeof plname
, "\"%.*s\"", pllen
, p
);
214 i
= dn_expand(abuf
, abuf
+alen
, p
, plname
, sizeof plname
- 1);
216 i
+= dn_expand(abuf
, abuf
+alen
, p
+i
, plname
+strlen(plname
),
217 sizeof plname
-strlen(plname
));
219 v
[j
] = 16777216u*p
[i
+4*j
] + 65536*p
[1+i
+4*j
]
220 + 256*p
[2+i
+4*j
] + p
[3+i
+4*j
];
221 snprintf(plname
+strlen(plname
),
222 sizeof plname
-strlen(plname
),
223 "(\n\t\t%u\t;serial (version)\n"
224 "\t\t%u\t;refresh period\n"
225 "\t\t%u\t;retry interval\n"
226 "\t\t%u\t;expire time\n"
227 "\t\t%u\t;default ttl\n"
228 "\t\t)", v
[0], v
[1], v
[2], v
[3], v
[4]);
231 pri
= 256*p
[0] + p
[1];
232 snprintf(plname
, sizeof plname
,
233 verbose
? "%d " : "(pri=%d) by ", pri
);
234 dn_expand(abuf
, abuf
+alen
, p
+2,
235 plname
+strlen(plname
),
236 sizeof plname
- strlen(plname
));
240 v
[j
] = 256*p
[2*j
] + p
[1+2*j
];
241 snprintf(plname
, sizeof plname
,
242 "%u %u %u ", v
[0], v
[1], v
[2]);
243 dn_expand(abuf
, abuf
+alen
, p
+6,
244 plname
+strlen(plname
),
245 sizeof plname
- strlen(plname
));
248 printf("%s unsupported RR type %u\n", rrname
, type
);
252 printf("%s\t%u\t%s %s\t%s\n",
253 rrname
, ttl
, "IN", rrt
[type
].name
, plname
);
254 } else if (rrt
[type
].msg
) {
255 printf("%s %s %s\n", rrname
, rrt
[type
].msg
, plname
);
258 if (!verbose
&& sec
==1) break;