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