This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
[oweals/busybox.git] / busybox / 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  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  */
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include <stdint.h>
34 #include <netdb.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
37 #include <netinet/in.h>
38 #include <resolv.h>
39 #include <arpa/inet.h>
40 #include "busybox.h"
41
42 /*
43  |  I'm only implementing non-interactive mode;
44  |  I totally forgot nslookup even had an interactive mode.
45  */
46
47 /* only works for IPv4 */
48 static int addr_fprint(char *addr)
49 {
50         uint8_t split[4];
51         uint32_t ip;
52         uint32_t *x = (uint32_t *) addr;
53
54         ip = ntohl(*x);
55         split[0] = (ip & 0xff000000) >> 24;
56         split[1] = (ip & 0x00ff0000) >> 16;
57         split[2] = (ip & 0x0000ff00) >> 8;
58         split[3] = (ip & 0x000000ff);
59         printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]);
60         return 0;
61 }
62
63 /* takes the NULL-terminated array h_addr_list, and
64  * prints its contents appropriately
65  */
66 static int addr_list_fprint(char **h_addr_list)
67 {
68         int i, j;
69         char *addr_string = (h_addr_list[1])
70                 ? "Addresses: " : "Address:   ";
71
72         printf("%s ", addr_string);
73         for (i = 0, j = 0; h_addr_list[i]; i++, j++) {
74                 addr_fprint(h_addr_list[i]);
75
76                 /* real nslookup does this */
77                 if (j == 4) {
78                         if (h_addr_list[i + 1]) {
79                                 printf("\n          ");
80                         }
81                         j = 0;
82                 } else {
83                         if (h_addr_list[i + 1]) {
84                                 printf(", ");
85                         }
86                 }
87
88         }
89         printf("\n");
90         return 0;
91 }
92
93 /* print the results as nslookup would */
94 static struct hostent *hostent_fprint(struct hostent *host, const char *server_host)
95 {
96         if (host) {
97                 printf("%s     %s\n", server_host, host->h_name);
98                 addr_list_fprint(host->h_addr_list);
99         } else {
100                 printf("*** Unknown host\n");
101         }
102         return host;
103 }
104
105 /* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+
106  * into a uint32_t
107  */
108 static uint32_t str_to_addr(const char *addr)
109 {
110         uint32_t split[4];
111         uint32_t ip;
112
113         sscanf(addr, "%d.%d.%d.%d",
114                    &split[0], &split[1], &split[2], &split[3]);
115
116         /* assuming sscanf worked */
117         ip = (split[0] << 24) |
118                 (split[1] << 16) | (split[2] << 8) | (split[3]);
119
120         return htonl(ip);
121 }
122
123 /* gethostbyaddr wrapper */
124 static struct hostent *gethostbyaddr_wrapper(const char *address)
125 {
126         struct in_addr addr;
127
128         addr.s_addr = str_to_addr(address);
129         return gethostbyaddr((char *) &addr, 4, AF_INET);       /* IPv4 only for now */
130 }
131
132 /* lookup the default nameserver and display it */
133 static inline void server_print(void)
134 {
135         struct sockaddr_in def = _res.nsaddr_list[0];
136         char *ip = inet_ntoa(def.sin_addr);
137
138         hostent_fprint(gethostbyaddr_wrapper(ip), "Server:");
139         printf("\n");
140 }
141
142 /* alter the global _res nameserver structure to use
143    an explicit dns server instead of what is in /etc/resolv.h */
144 static inline void set_default_dns(char *server)
145 {
146         struct in_addr server_in_addr;
147
148         if(inet_aton(server,&server_in_addr))
149         {
150                 _res.nscount = 1;
151                 _res.nsaddr_list[0].sin_addr = server_in_addr;
152         }
153 }
154
155 /* naive function to check whether char *s is an ip address */
156 static int is_ip_address(const char *s)
157 {
158         while (*s) {
159                 if ((isdigit(*s)) || (*s == '.')) {
160                         s++;
161                         continue;
162                 }
163                 return 0;
164         }
165         return 1;
166 }
167
168 /* ________________________________________________________________________ */
169 int nslookup_main(int argc, char **argv)
170 {
171         struct hostent *host;
172
173         /*
174         * initialize DNS structure _res used in printing the default
175         * name server and in the explicit name server option feature.
176         */
177
178         res_init();
179
180         /*
181         * We allow 1 or 2 arguments.
182         * The first is the name to be looked up and the second is an
183         * optional DNS server with which to do the lookup.
184         * More than 3 arguments is an error to follow the pattern of the
185         * standard nslookup
186         */
187
188         if (argc < 2 || *argv[1]=='-' || argc > 3)
189                 bb_show_usage();
190         else if(argc == 3)
191                 set_default_dns(argv[2]);
192
193         server_print();
194         if (is_ip_address(argv[1])) {
195                 host = gethostbyaddr_wrapper(argv[1]);
196         } else {
197                 host = xgethostbyname(argv[1]);
198         }
199         hostent_fprint(host, "Name:  ");
200         if (host) {
201                 return EXIT_SUCCESS;
202         }
203         return EXIT_FAILURE;
204 }
205
206 /* $Id: nslookup.c,v 1.33 2004/10/13 07:25:01 andersen Exp $ */