small ipv6 doc changes; nslookup a tiny bit smaller
[platform/upstream/busybox.git] / networking / nslookup.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini nslookup implementation for busybox
4  *
5  * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
6  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7  *
8  * Correct default name server display and explicit name server option
9  * added by Ben Zeckel <bzeckel@hmc.edu> June 2001
10  *
11  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
12  */
13
14 #include <resolv.h>
15 #include "busybox.h"
16
17 /*
18  *  I'm only implementing non-interactive mode;
19  *  I totally forgot nslookup even had an interactive mode.
20  */
21
22 /* Examples of 'standard' nslookup output
23  * $ nslookup yahoo.com
24  * Server:         128.193.0.10
25  * Address:        128.193.0.10#53
26  * 
27  * Non-authoritative answer:
28  * Name:   yahoo.com
29  * Address: 216.109.112.135
30  * Name:   yahoo.com
31  * Address: 66.94.234.13
32  *
33  * $ nslookup 204.152.191.37
34  * Server:         128.193.4.20
35  * Address:        128.193.4.20#53
36  * 
37  * Non-authoritative answer:
38  * 37.191.152.204.in-addr.arpa     canonical name = 37.32-27.191.152.204.in-addr.arpa.
39  * 37.32-27.191.152.204.in-addr.arpa       name = zeus-pub2.kernel.org.
40  * 
41  * Authoritative answers can be found from:
42  * 32-27.191.152.204.in-addr.arpa  nameserver = ns1.kernel.org.
43  * 32-27.191.152.204.in-addr.arpa  nameserver = ns2.kernel.org.
44  * 32-27.191.152.204.in-addr.arpa  nameserver = ns3.kernel.org.
45  * ns1.kernel.org  internet address = 140.211.167.34
46  * ns2.kernel.org  internet address = 204.152.191.4
47  * ns3.kernel.org  internet address = 204.152.191.36
48  */
49
50 static int sockaddr_to_dotted(struct sockaddr *saddr, char *buf, int buflen)
51 {
52         if (buflen <= 0) return -1;
53         buf[0] = '\0';
54         if (saddr->sa_family == AF_INET) {
55                 inet_ntop(AF_INET, &((struct sockaddr_in*)saddr)->sin_addr, buf, buflen);
56                 return 0;
57         }
58         if (saddr->sa_family == AF_INET6) {
59                 inet_ntop(AF_INET6, &((struct sockaddr_in6*)saddr)->sin6_addr, buf, buflen);
60                 return 0;
61         }
62         return -1;
63 }
64
65 static int print_host(const char *hostname, const char *header)
66 {
67         char str[128];  /* IPv6 address will fit, hostnames hopefully too */
68         struct addrinfo *result = NULL;
69         int rc;
70         struct addrinfo hint;
71
72         memset(&hint, 0 , sizeof(hint));
73         /* hint.ai_family = AF_UNSPEC; - zero anyway */
74         /* Needed. Or else we will get each address thrice (or more)
75          * for each possible socket type (tcp,udp,raw...): */
76         hint.ai_socktype = SOCK_STREAM;
77         // hint.ai_flags = AI_CANONNAME;
78         rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
79         if (!rc) {
80                 struct addrinfo *cur = result;
81                 // printf("%s\n", cur->ai_canonname); ?
82                 while (cur) {
83                         sockaddr_to_dotted(cur->ai_addr, str, sizeof(str));
84                         printf("%s  %s\nAddress: %s", header, hostname, str);
85                         s[0] = ' ';
86                         if (getnameinfo(cur->ai_addr, cur->ai_addrlen, str+1, sizeof(str)-1, NULL, 0, NI_NAMEREQD))
87                                 str[0] = '\0';
88                         puts(str);
89                         cur = cur->ai_next;
90                 }
91         } else {
92                 bb_error_msg("getaddrinfo('%s') failed: %s", hostname, gai_strerror(rc));
93         }
94         freeaddrinfo(result);
95         return (rc != 0);
96 }
97
98
99 /* alter the global _res nameserver structure to use
100    an explicit dns server instead of what is in /etc/resolv.h */
101 static void set_default_dns(char *server)
102 {
103         struct in_addr server_in_addr;
104
105         if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
106                 _res.nscount = 1;
107                 _res.nsaddr_list[0].sin_addr = server_in_addr;
108         }
109 }
110
111
112 /* lookup the default nameserver and display it */
113 static void server_print(void)
114 {
115         char str[INET6_ADDRSTRLEN];
116
117         sockaddr_to_dotted((struct sockaddr*)&_res.nsaddr_list[0], str, sizeof(str));
118         print_host(str, "Server:");
119         puts("");
120 }
121
122
123 int nslookup_main(int argc, char **argv)
124 {
125         /*
126         * initialize DNS structure _res used in printing the default
127         * name server and in the explicit name server option feature.
128         */
129
130         res_init();
131
132         /*
133         * We allow 1 or 2 arguments.
134         * The first is the name to be looked up and the second is an
135         * optional DNS server with which to do the lookup.
136         * More than 3 arguments is an error to follow the pattern of the
137         * standard nslookup
138         */
139
140         if (argc < 2 || *argv[1] == '-' || argc > 3)
141                 bb_show_usage();
142         else if(argc == 3)
143                 set_default_dns(argv[2]);
144
145         server_print();
146         return print_host(argv[1], "Name:  ");
147 }
148
149 /* $Id: nslookup.c,v 1.33 2004/10/13 07:25:01 andersen Exp $ */